标准 Kotlin 库中有哪些 Java 8 Stream.collect 等效项? [英] What Java 8 Stream.collect equivalents are available in the standard Kotlin library?

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

问题描述

在 Java 8 中,有 Stream.collect 允许对集合进行聚合.在 Kotlin 中,这不以相同的方式存在,除了可能作为 stdlib 中的扩展函数集合.但尚不清楚不同用例的等效项是什么.

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.

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

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.

就展示 Kotlin 集合示例的在线资源而言,它们通常是微不足道的,并不能真正与相同的用例进行比较.什么是真正符合 Java 8 Stream.collect 记录的案例的好例子?清单是:

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:

  • 将名称累积到列表中
  • 将名称累积到 TreeSet 中
  • 将元素转换为字符串并将它们连接起来,用逗号分隔
  • 计算员工工资总额
  • 按部门对员工进行分组
  • 按部门计算工资总额
  • 将学生分为合格和不合格

在上面链接的 JavaDoc 中有详细信息.

With details in the JavaDoc linked above.

注意:这个问题是作者特意写的和回答的(Self-Answered Questions),以便在 SO 中提供对常见 Kotlin 主题的惯用答案.还要澄清一些为 Kotlin alpha 编写的非常旧的答案,这些答案对于当前的 Kotlin 来说是不准确的.

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.

推荐答案

Kotlin stdlib 中有求平均值、计数、distinct、过滤、查找、分组、连接、映射、最小值、最大值、分区、切片、排序的函数,求和,到/从数组,到/从列表,到/从地图,联合,共同迭代,所有功能范式等等.所以你可以使用它们来创建小的 1-liners,并且不需要使用 Java 8 的更复杂的语法.

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.

我认为内置的 Java 8 Collectors 类唯一缺少的是总结(但在 这个问题的另一个答案是一个简单的解决方案).

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).

两者都缺少一件事是按计数进行批处理,这可以在另一个堆栈溢出答案中看到,并且有一个简单的答案以及.另一个有趣的案例来自 Stack Overflow:Idiomatic使用 Kotlin 将序列溢出到三个列表中的方法.如果您想出于其他目的创建类似 Stream.collect 的内容,请参阅 Kotlin 中的自定义 Stream.collect

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

编辑 11.08.2017: 在 kotlin 1.2 M2 中添加了分块/窗口化集合操作,请参阅 https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/

EDIT 11.08.2017: Chunked/windowed collection operations were added in kotlin 1.2 M2, see https://blog.jetbrains.com/kotlin/2017/08/kotlin-1-2-m2-is-out/

探索 kotlin 的 API 参考总是好的.在创建可能已经存在的新函数之前,将集合作为一个整体.

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

以下是一些从 Java 8 Stream.collect 示例到 Kotlin 中等效项的转换:

Here are some conversions from Java 8 Stream.collect examples to the equivalent in 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.如果您有更多用例,请在评论中添加它们,我们可以看到!

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!

如果你想延迟处理一个链,你可以在链之前使用 asSequence() 转换为 Sequence.在函数链的末尾,您通常还会得到一个 Sequence.然后你可以使用toList()toSet()toMap()或其他一些函数来具体化Sequence 最后.

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()

为什么没有类型?!?

您会注意到 Kotlin 示例没有指定类型.这是因为 Kotlin 具有完整的类型推断并且在编译时是完全类型安全的.比 Java 更重要,因为它还具有可为空类型,并且可以帮助防止可怕的 NPE.所以在 Kotlin 中:

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 }

等同于:

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

因为 Kotlin 知道 people 是什么,并且 people.ageInt 因此过滤器表达式只允许与 进行比较Int,并且 people.name 是一个 String 因此 map 步骤产生一个 Listcode>(只读List of String).

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).

现在,如果 people 可能是 null,就像在 List? 中那样:

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

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

返回一个 List? 需要检查空值(或使用其他 Kotlin 运算符之一获取可空值,请参阅此 Kotlin 处理可空值的惯用方法以及 在 Kotlin 中处理可空列表或空列表的惯用方式)

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)

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

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