当前位置: 首页 > 面试题库 >

标准Kotlin库中提供了哪些Java 8 Stream.collect等效项?

戚宏扬
2023-03-14
问题内容

在Java
8中,Stream.collect它允许对集合进行聚合。在Kotlin中,除了以stdlib中的扩展功能的集合形式存在之外,这并不完全相同。但尚不清楚不同用例的等效性。

例如,在JavaDocCollectors的顶部是为Java
8编写的示例,将它们移植到Kolin时,在不同的JDK版本上不能使用Java 8类,因此可能应该以不同的方式编写它们。

在网上显示Kotlin集合示例的资源方面,它们通常是微不足道的,不能真正与相同的用例进行比较。有什么真正与案例相匹配的好示例,例如针对Java
8记录的案例Stream.collect?列表是:

  • 将名称累积到列表中
  • 将名称累积到TreeSet中
  • 将元素转换为字符串并将其连接起来,并以逗号分隔
  • 计算员工的薪金总额
  • 按部门分组员工
  • 按部门计算薪金总额
  • 划分学生通过和失败

在上面链接的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结尾。

// 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.ageInt因此,过滤器表达式只允许比较的Int,那people.name是一个String因此map步骤产生List<String>(只读ListString)。

现在,如果people是可能的null,因为,在一List<People>?则:

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

返回List<String>?需要进行空检查的a( 或将其他Kotlin运算符之一用于可空值,请参阅此
Kotlin惯用方式来处理可空值,以及用于处理Kotlin中可空或空列表的

惯用方式

也可以看看:

  • 有关Iterable扩展功能的 API参考
  • 数组扩展功能的 API参考
  • List扩展功能的 API参考
  • 用于Map扩展功能的 API参考


 类似资料:
  • 在Java8中,有,它允许对集合进行聚合。在Kotlin中,除了可能作为stdlib中的扩展函数集合之外,这并不是以同样的方式存在的。但不清楚不同用例的等价物是什么。 例如,JavaDoc For的顶部是为Java8编写的示例,当将它们移植到Kolin时,您不能在不同的JDK版本上使用Java8类,因此它们可能应该以不同的方式编写。 就展示Kotlin集合示例的在线资源而言,它们通常是微不足道的,

  • 本文向大家介绍HTML5标准提供了哪些新的API?你有用过哪些?相关面试题,主要包含被问及HTML5标准提供了哪些新的API?你有用过哪些?时的应答技巧和注意事项,需要的朋友参考一下 两个选择器API 地理定位API 多媒体API 拖放API 文件API XHR2 本地储存API canvas svg

  • 我本来也是希望看到更多的标准库文件的。然而,(我改观是因为我)注意到标准库文件中定义的篇幅就占了超过75%的规范性文字(而且这些还不包括作为参考文献的C标准库文件)。虽然我们中的许多人也很希望看到更多的标准库文件,但是没人责备库工作组的懈怠。值得一提的是,C++98标准库已通过新语言特性的应用,如初始化列表 ,右值引用 ,可变参数模板 和constexpr(常量表达式) 而取得了显著改善。相比C+

  • Kotlin编译器给了我以下警告: 警告:(399,1)Kotlin:内联“…”的预期性能影响可能是无关紧要的。内联最适用于具有lambda参数的函数 在这种情况下,我想取消显示此警告。但是,我不知道给什么值,也找不到任何文档说明接受什么值。 可以为提供哪些可能的值,它们是什么意思?

  • 本文向大家介绍npm提供了哪些钩子?各有什么作用?相关面试题,主要包含被问及npm提供了哪些钩子?各有什么作用?时的应答技巧和注意事项,需要的朋友参考一下 npm 拥有以下的钩子命令:对于任何在 package.json 的 scripts 字段中定义的命令,可以通过 pre 以及 post 名称前缀,额外定义该任务在执行前、后的额外执行的钩子命令。例如: { "scripts": { "prem

  • 本文向大家介绍系统测试标准有哪些?相关面试题,主要包含被问及系统测试标准有哪些?时的应答技巧和注意事项,需要的朋友参考一下 不存在致命或严重级别的BUG 不存在优先级为P1的BUG 遗留问题不能大于总BUG数的8% 遗留问题不能明显影响用户使用