什么Java 8 Stream.collect等价物在标准的Kotlin库中可用? [英] What Java 8 Stream.collect equivalents are available in the standard Kotlin library?

查看:2039
本文介绍了什么Java 8 Stream.collect等价物在标准的Kotlin库中可用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Java 8中,有 Stream.collect 允许集合上的聚合。在Kotlin中,这不以同样的方式存在,除了可能作为stdlib中的扩展函数的集合。但是不清楚不同用例的等效性。



例如,在 Collectors 的JavaDoc顶部是为Java 8编写的示例,当将它们移植到Kolin时,不能使用Java 8类在不同的JDK版本上,所以可能应该写成不同的。



在资源在线显示Kotlin集合的例子,他们通常是微不足道的,并不真正比较相同的用例。什么是很好的例子,真正匹配的案例,如记录为Java 8 Stream.collect ?列表中有:




  • 将名称累积到列表中

  • 将名称累积到TreeSet

  • 将元素转换为字符串并用逗号分隔

  • 计算员工的工资总额


  • 按部门计算工资总额

  • 将学生分成通过和失败



有关上述链接的JavaDoc的详细信息。



注意: >这个问题是由作者故意写和回答的(自我回答的问题),以便常用的Kotlin主题的惯用答案出现在SO中。还要澄清一些为Kotlin的alphas写的,对当前Kotlin不准确的老的答案。


解决方案

这些示例和更多内容现在在堆栈中维护溢出文档



Kotlin stdlib中有用于平均,计数,不同,过滤,查找,分组,连接,映射,最小, ,切片,排序,求和,到/从数组,到/从列表,到/从映射,联合,协同,所有的功能范例等等。所以你可以使用它们来创建一个简单的1-liners,并且没有必要使用更复杂的Java 8语法。



我认为唯一缺少的来自内置的Java 8 Collectors 类是摘要(但在另一个答案这个问题是一个简单的解决方案)。



两者之间缺少的一件事是按计数进行批量处理,这在另一个Stack Overflow answer ,并有一个简单的答案。另一个有趣的情况是这也是从Stack Overflow:惯用语使用Kotlin将溢出序列分成三个列表。如果您想要创建 Stream.collect 以实现其他目的,请参阅自定义流。收集在Kotlin



总是好的探索用于kotlin.collections的API参考作为一个整体,然后创建可能已经存在的新函数。



这里是一些从Java 8 Stream.collect 到Kotlin中的等价类型的转换:



将名称累加到列表中

  // Java:
List< String> list = people.stream()。map(Person :: getName).collect(Collectors.toList());



  // Kotlin:
val list = people .map {it.name} // toList()不需要

并连接起来,并以逗号分隔

  // Java:
String join = things.stream()
.map(Object :: toString)
.collect(Collectors.joining(,));



  // Kotlin:
val joined = things .joinToString(,)

计算员工工资总额 / p>

  // Java:
int total = employees.stream()
.collect(Collectors.summingInt(Employee :: getSalary)));



  // Kotlin:
val total = .sumBy {it.salary}

按部门分组员工

  // Java:
Map< Department,List< Employee> byDept
= employees.stream()
.collect(Collectors.groupingBy(Employee :: getDepartment));



  // Kotlin:
val byDept = employees .groupBy {it.department}

按部门计算工资总和 / p>

  // Java:
Map< Department,Integer> totalByDept
= employees.stream()
.collect(Collectors.groupingBy(Employee :: getDepartment,
Collectors.summingInt(Employee :: getSalary)));



  // Kotlin:
val totalByDept = employees .groupBy {it.dept} .mapValues {it.value.sumBy {it.salary}}

将学生分成传递和失败

  // Java:
Map< Boolean,List< Student>> passedFailing =
students.stream()
.collect(Collectors.partitioningBy(s - > s.getGrade()> = PASS_THRESHOLD));



  // Kotlin:
val passingFailing = students .partition {it.grade> = PASS_THRESHOLD}

男性成员姓名

  // Java:
List< String> namesOfMaleMembersCollect = roster
.stream()
.filter(p - > p.getGender()== Person.Sex.MALE)
.map(p - > p.getName ))
.collect(Collectors.toList());



  // Kotlin:
val namesOfMaleMembers = roster .filter {it.gender == Person.Sex.MALE} .map {it.name}

按性别列在成员名单中的成员名称

  
Map< Person.Sex,List< String>> namesByGender =
roster.stream()。collect(
Collectors.groupingBy(
Person :: getGender,
Collectors.mapping(
Person :: getName,
Collectors.toList())));



  // Kotlin:
val namesByGender = roster .groupBy {it.gender} .mapValues {it.value.map {it.name}}

将列表过滤到另一个列表

  // Java:
List< String> filtered = items.stream()
.filter(item - > item.startsWith(o))
.collect(Collectors.toList



  // Kotlin:
val filtered = items .filter {item.startsWith('o')}

/ strong>

  // Java:
String shortest = items.stream
.min(Comparator.comparing(item - > item.length()))
.get();



  // Kotlin:
val short = items .minBy {it.length}

在应用过滤器后对列表中的项目进行计数

  // Java:
long count = items.stream filter(item - > item.startsWith(t))。count();



  // Kotlin:
val count = items .filter {it.startsWith('t')} .size
//但最好不要过滤,但是使用谓词
val count = items.count {it.startsWith('t') }

并在它上...在所有情况下,没有特殊的折叠,缩小或其他功能需要模仿 Stream.collect 。如果您有其他用例,请在评论中添加它们,我们可以看到!



关于懒惰



想要延迟处理链,可以在链之前使用 asSequence()转换为序列。在函数链的末尾,通常最后还有一个 Sequence 。然后可以使用 toList() toSet() toMap c $ c>或一些其他函数来实现 Sequence 结束。

  //切换到和从lazy 
val someList = items.asSequence()。filter {...} .take(10).map {...} .toList()

//切换到lazy,但sorted()在最后再次出现
val someList = items.asSequence()。filter {...} .take(10).map {... } .sorted()



为什么没有Types?!?



你会注意到Kotlin的例子没有指定类型。这是因为Kotlin具有完整的类型推断,并且在编译时是完全类型安全的。比Java更多,因为它也有可空类型,可以帮助防止可怕的NPE。所以这在Kotlin:

  val someList = people.filter {it.age< = 30} .map {it.name } 

与以下相同:

  val someList:List< String> = people.filter {it.age< = 30} .map {it.name} 

Kotlin知道是什么, people.age Int 因此过滤器表达式只允许与 Int 进行比较, people.name String ,因此 map 步骤产生一个 List< String> (readonly <$现在,如果<$ c>

$ c>人可能 null ,因为在列表<人>?那么:

  val someList = people?.filter {it.age< = 30}?map {it.name} 

返回 List< String>?将需要为null选中(或使用其他Kotlin运算符作为可空值,请参阅此 Kotlin处理可空值的常用方法以及在Kotlin中处理可空或空列表的惯用方法



另请参阅:




In Java 8, there is Stream.collect which allows aggregations on collections. In Kotlin, this does not exist in the same way, other than maybe as a collection of extension functions in the stdlib. But it isn't clear what the equivalences are for different use cases.

For example, at the top of the JavaDoc for Collectors are examples written for Java 8, and when porting them to Kolin you can't use the Java 8 classes when on a different JDK version, so likely they should be written differently.

In terms of resources online showing examples of Kotlin collections, they are typically trivial and don't really compare to the same use cases. What are good examples that really match the cases such as documented for Java 8 Stream.collect? The list there is:

  • Accumulate names into a List
  • Accumulate names into a TreeSet
  • Convert elements to strings and concatenate them, separated by commas
  • Compute sum of salaries of employee
  • Group employees by department
  • Compute sum of salaries by department
  • Partition students into passing and failing

With details in the JavaDoc linked above.

Note: this question is intentionally written and answered by the author (Self-Answered Questions), so that the idiomatic answers to commonly asked Kotlin topics are present in SO. Also to clarify some really old answers written for alphas of Kotlin that are not accurate for current-day Kotlin.

解决方案

These examples and more, are now maintained in Stack Overflow Documentation

There are functions in the Kotlin stdlib for average, count, distinct,filtering, finding, grouping, joining, mapping, min, max, partitioning, slicing, sorting, summing, to/from arrays, to/from lists, to/from maps, union, co-iteration, all the functional paradigms, and more. So you can use those to create little 1-liners and there is no need to use the more complicated syntax of Java 8.

I think the only thing missing from the built-in Java 8 Collectors class is summarization (but in another answer to this question is a simple solution).

One thing missing from both is batching by count, which is seen in another Stack Overflow answer and has a simple answer as well. Another interesting case is this one also from Stack Overflow: Idiomatic way to spilt sequence into three lists using Kotlin. And if you want to create something like Stream.collect for another purpose, see Custom Stream.collect in Kotlin

It is always good to explore the API Reference for kotlin.collections as a whole before creating new functions that might already exist there.

Here are some conversions from Java 8 Stream.collect examples to the equivalent in Kotlin:

Accumulate names into a List

// Java:  
List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());

// Kotlin:
val list = people.map { it.name }  // toList() not needed

Convert elements to strings and concatenate them, separated by commas

// Java:
String joined = things.stream()
                       .map(Object::toString)
                       .collect(Collectors.joining(", "));

// Kotlin:
val joined = things.joinToString(", ")

Compute sum of salaries of employee

// Java:
int total = employees.stream()
                      .collect(Collectors.summingInt(Employee::getSalary)));

// Kotlin:
val total = employees.sumBy { it.salary }

Group employees by department

// Java:
Map<Department, List<Employee>> byDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment));

// Kotlin:
val byDept = employees.groupBy { it.department }

Compute sum of salaries by department

// Java:
Map<Department, Integer> totalByDept
     = employees.stream()
                .collect(Collectors.groupingBy(Employee::getDepartment,
                     Collectors.summingInt(Employee::getSalary)));

// Kotlin:
val totalByDept = employees.groupBy { it.dept }.mapValues { it.value.sumBy { it.salary }}

Partition students into passing and failing

// Java:
Map<Boolean, List<Student>> passingFailing =
     students.stream()
             .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));

// Kotlin:
val passingFailing = students.partition { it.grade >= PASS_THRESHOLD }

Names of male members

// Java:
List<String> namesOfMaleMembersCollect = roster
    .stream()
    .filter(p -> p.getGender() == Person.Sex.MALE)
    .map(p -> p.getName())
    .collect(Collectors.toList());

// Kotlin:
val namesOfMaleMembers = roster.filter { it.gender == Person.Sex.MALE }.map { it.name }

Group names of members in roster by gender

// Java:
Map<Person.Sex, List<String>> namesByGender =
      roster.stream().collect(
        Collectors.groupingBy(
            Person::getGender,                      
            Collectors.mapping(
                Person::getName,
                Collectors.toList())));

// Kotlin:
val namesByGender = roster.groupBy { it.gender }.mapValues { it.value.map { it.name } }   

Filter a list to another list

// Java:
List<String> filtered = items.stream()
    .filter( item -> item.startsWith("o") )
    .collect(Collectors.toList());

// Kotlin:
val filtered = items.filter { item.startsWith('o') } 

Finding shortest string a list

// Java:
String shortest = items.stream()
    .min(Comparator.comparing(item -> item.length()))
    .get();

// Kotlin:
val shortest = items.minBy { it.length }

Counting items in a list after filter is applied

// Java:
long count = items.stream().filter( item -> item.startsWith("t")).count();

// Kotlin:
val count = items.filter { it.startsWith('t') }.size
// but better to not filter, but count with a predicate
val count = items.count { it.startsWith('t') }

and on it goes... In all cases, no special fold, reduce, or other functionality was required to mimic Stream.collect. If you have further use cases, add them in comments and we can see!

About laziness

If you want to lazy process a chain, you can convert to a Sequence using asSequence() before the chain. At the end of the chain of functions, you usually end up with a Sequence as well. Then you can use toList(), toSet(), toMap() or some other function to materialize the Sequence at the end.

// switch to and from lazy
val someList = items.asSequence().filter { ... }.take(10).map { ... }.toList()

// switch to lazy, but sorted() brings us out again at the end
val someList = items.asSequence().filter { ... }.take(10).map { ... }.sorted()

Why are there no Types?!?

You will notice the Kotlin examples do not specify the types. This is because Kotlin has full type inference and is completely type safe at compile time. More so than Java because it also has nullable types and can help prevent the dreaded NPE. So this in Kotlin:

val someList = people.filter { it.age <= 30 }.map { it.name }

is the same as:

val someList: List<String> = people.filter { it.age <= 30 }.map { it.name }

Because Kotlin knows what people is, and that people.age is Int therefore the filter expression only allows comparison to an Int, and that people.name is a String therefore the map step produces a List<String> (readonly List of String).

Now, if people were possibly null, as-in a List<People>? then:

val someList = people?.filter { it.age <= 30 }?.map { it.name }

Returns a List<String>? that would need to be null checked (or use one of the other Kotlin operators for nullable values, see this Kotlin idiomatic way to deal with nullable values and also Idiomatic way of handling nullable or empty list in Kotlin)

See also:

这篇关于什么Java 8 Stream.collect等价物在标准的Kotlin库中可用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆