Stream 虽然已经提供了不少终止操作,但是可能在有些场景下还是无法满足你的使用要求。没关系,如果你发现你想要的终止操作功能接口 Stream 没有提供,不妨试试从 collect 方法查找一下,很大概率上你会有意外收获。
方法定义
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);<R, A> R collect(Collector<? super T, A, R> collector);
collect 提供了两个方法,一个是三参数方法,单看参数的话,其实和 reduce 特别像。单参数的方法,需要传入一个收集器。其实点进收集器内部不难发现,Collector 内部定义了三参数方法需要的所有内容。二者的作用都是将流内元素按照一定的要求汇聚成一个最终结果。
1 | public interface Collector<T, A, R> { |
从 collect 方法的返回类型来看,collect 方法的主要作用是将流所有元素汇聚成一个值。从某种意义讲,其实也是 reduce。
三参数 collect
从参数来看,三参数的 collect 很像 reduce,其实从实现来看,也有些像。
1 | public final <R> R reduce(R identity, |
和 reduce 一样,在串行流下,combiner 也是不会生效参与运算的。
1 | public void collectTest() { |
在串行流下,collect 仍然将流合并成了一个 ArrayList,并正常输出,但是却没有出现我们主动打印的 this is the third parameter。
[1, 2, 3, 4, 5]
当然,大多数情况下我们是可以不用三参数方法,因为 JDK 贴心的为我们提供各种各样的收集器。
带收集器的 collect
collect 方法可以传入一个收集器,方法会根据收集器内部的定义,来自动完成我们想要的功能。
比如,我们想要将流内元素转成一个 List,可以用下面的方式来实现。
1 | public void collectTest2() { |
方法最终的结果,和我们自己用三参数的方式写的代码输出的结果,是一致的。
对于常用的收集器,JDK 专门提供了一个 Collectors 类,定义了我们常用的不常用的收集器。
收集器 Collectors
转成集合
| 方法 | 作用 |
|---|---|
| toCollection | 将数据转成Collection |
| toList | 将数据转成List |
| toSet | 将数据转成Set |
| toMap | 将数据转成Map |
| toConcurrentMap | 将数据转成concurrentMap |
转成值
| 方法 | 作用 |
|---|---|
| counting | 统计流元素个数 |
| joining | 拼接成一个字符串 |
| minBy | 根据比较器取最小值 |
| maxBy | 根据比较器取最大值 |
| reducing | 数据汇聚,类似 reduce |
| averagingInt | int流求平均数 |
| averagingLong | long流求平均数 |
| averagingDouble | double流求平均数 |
| summingInt | int流求总和 |
| summarizingLong | long流求总和 |
| summarizingDouble | double流求总和 |
分组与分块
| 方法 | 作用 |
|---|---|
| collectingAndThen | 收集数据后再做一些额外操作 |
| mapping | 先map,再收集 |
| groupingBy | 数据分组 |
| groupingByConcurrent | 并行数据分组 |
| partitioningBy | 数据分成多部分 |
总结
collect方法,我们可以自己使用三参数方法来调用,也可以直接用JDK提供好的收集器。- 收集器汇总在
java.util.stream.collectors。