在Java 8中,Stream.collect它允许对集合进行聚合。在Kotlin中,除了以stdlib中的扩展功能的集合形式存在之外,这并不完全相同。但尚不清楚不同用例的等效性。
Stream.collect
例如,在JavaDocCollectors的顶部是为Java 8编写的示例,将它们移植到Kolin时,在不同的JDK版本上不能使用Java 8类,因此可能应该以不同的方式编写它们。
Collectors
在网上显示Kotlin集合示例的资源方面,它们通常是微不足道的,不能真正与相同的用例进行比较。有什么真正与案例相匹配的好示例,例如针对Java 8记录的案例Stream.collect?列表是:
在上面链接的JavaDoc中有详细信息。
注意: 这个问题是作者故意写和回答的(“自我回答的问题”),因此对常见Kotlin主题的惯用答案出现在SO中。同时也要澄清一些针对Kotlin字母的非常古老的答案,这些答案对于当今的Kotlin而言并不准确。
Kotlin stdlib中有一些功能,用于平均,计数,不同,过滤,查找,分组,联接,映射,最小,最大,分区,切片,排序,求和,到/自数组,到/自列表,到/自地图,联合,共同迭代,所有功能范例等。因此,您可以使用它们来创建少量的1-liner,而无需使用Java8的更复杂的语法。
编辑11.08.2017: 在kotlin 1.2 M2中添加了分块/窗口收集操作,请参阅https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is- out/
在创建可能已经存在的新函数之前,最好先整体探讨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() not needed
将元素转换为字符串并将其连接起来,并以逗号分隔
// Java: String joined = things.stream() .map(Object::toString) .collect(Collectors.joining(", ")); // Kotlin: val joined = things.joinToString(", ")
计算员工的薪金总额
// Java: int total = employees.stream() .collect(Collectors.summingInt(Employee::getSalary))); // Kotlin: val total = employees.sumBy { it.salary }
按部门分组员工
// Java: Map<Department, List<Employee>> byDept = employees.stream() .collect(Collectors.groupingBy(Employee::getDepartment)); // Kotlin: val byDept = employees.groupBy { it.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 }}
划分学生通过和失败
// 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 }
男性成员的名字
// Java: List<String> namesOfMaleMembers = 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 }
按性别列出的成员名单名称
// 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 } }
将列表过滤到另一个列表
// Java: List<String> filtered = items.stream() .filter( item -> item.startsWith("o") ) .collect(Collectors.toList()); // Kotlin: val filtered = items.filter { it.startsWith('o') }
查找最短的字符串列表
// Java: String shortest = items.stream() .min(Comparator.comparing(item -> item.length())) .get(); // Kotlin: val shortest = items.minBy { it.length }
应用过滤器后对列表中的项目进行计数
// 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') }
并继续下去…在所有情况下,都不需要模仿特殊的折叠,缩小或其他功能Stream.collect。如果您还有其他用例,请在注释中添加它们,我们可以看到!
如果您要延迟处理链,可以在链之前转换为Sequence使用asSequence()。在功能链的最后,您通常也以一个结尾Sequence。然后你可以使用toList(),toSet(),toMap()或其他一些功能兑现的Sequence结尾。
Sequence
asSequence()
toList()
toSet()
toMap()
// 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()
您会注意到Kotlin示例未指定类型。这是因为Kotlin具有完整类型推断,并且在编译时是完全类型安全的。它比Java更是如此,因为它还具有可为空的类型,并且可以帮助防止可怕的NPE。所以在科特林:
val someList = people.filter { it.age <= 30 }.map { it.name }
是相同的:
val someList: List<String> = people.filter { it.age <= 30 }.map { it.name }
因为科特林知道什么people是,这people.age是Int因此,过滤器表达式只允许比较的Int,那people.name是一个String因此map步骤产生List<String>(只读List的String)。
people
people.age
Int
people.name
String
map
List<String>
List
现在,如果people是可能的null,因为,在一List<People>?则:
null
List<People>?
val someList = people?.filter { it.age <= 30 }?.map { it.name }
返回List<String>?需要进行空检查的a( 或将其他Kotlin运算符之一用于可空值,请参阅此 Kotlin惯用方式来处理可空值,以及用于处理Kotlin中可空或空列表的 惯用方式 )
List<String>?