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。