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
。