1. 怎样理解 collect
- 定义:
<R, A> R collect(Collector<? super T, A, R> collector)
- 它接受一个收集器
collector
作为参数,类型是Collector
,这是一个接口
2. 与 toList
类似的容器收集器还有哪些
toSet
:可以排重。toList
背后的容器是ArrayList
,toSet
背后的容器是HashSet
toCollection
:通用的容器收集器,可以用于任何Collection
接口的实现类。比如,如果希望排重但又希望保留出现的顺序,可以使用LinkedHashSet
,Collector
可以这么创建:Collectors.toCollection(LinkedHashSet::new);
toMap
:将元素流转换为一个Map
。Map
有键和值两部分,toMap
至少需要两个参数,一个将元素转换为键,另一个将元素转换为值
3. 怎样理解字符串收集器
除了将元素流收集到容器中,另一个常见的操作是收集为一个字符串
针对这种需求,
Collectors
提供了joining
收集器public static Collector<CharSequence, ?, String> joining()
:简单地把元素连接起来public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
:支持一个分隔符,还可以给整个结果字符串加前缀和后缀
joining
收集器的内部也利用了StringBuilder
4. 怎样理解分组
分组类似于数据库查询语言 SQL 中的 group by 语句,它将元素流中的每个元素分到一个组,可以针对分组再进行处理和收集
最基本的分组收集器为:
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
- 参数是一个类型为
Function
的分组器classifier
,它将类型为T
的元素转换为类型为K
的一个值,这个值表示分组值 - 所有分组值一样的元素会被归为同一个组,放到一个列表中,所以返回值类型是
Map<K, List<T>>
- 参数是一个类型为
分组计数、找最大/最小元素:将元素按一定标准分为多组,然后计算每组的个数,按一定标准找最大或最小元素。
Collectors
提供了一些对应的收集器,一般用作下游收集器,比如maxBy
、minBy
、counting
分组数值统计:除了基本的分组计数,还经常需要进行一些分组数值统计,比如求学生分数的和、平均分、最高分、最低分等,针对
int
、long
和double
类型,Collectors
提供了专门的收集器分组内的
map
:对于每个分组内的元素,我们感兴趣的可能不是元素本身,而是它的某部分信息- 在 Stream API 中,
Stream
有map
方法,可以将元素进行转换,Collectors
也为分组元素提供了函数mapping
:交给下游收集器downstream
的不再是元素本身,而是应用转换函数mapper
之后的结果 Stream
有flatMap
方法,Java 9 为Collectors
增加了分组内的flatMap
方法flatMapping
,它与mapping
的关系如同Stream
中flatMap
和map
的关系- 分组结果处理(
filter
、sort
、skip
、limit
):Collector
没有专门的收集器,但有一个通用的方法:public static<T, A, R, RR> Collector<T, A, RR> collectingAndThen(Collector<T, A, R> downstream, Function<R, RR> finisher)
,接受一个下游收集器downstream
和 一个finisher
,返回一个收集器 - 分区:分组的一个特殊情况是分区,就是将流按
true
、false
分为两个组。Collectors
有专门的分区函数partitioningBy()
- 多级分组:
groupingBy
和parttitionBy
都可以接受一个下游收集器,对同一个分组或分区内的元素进行进一步收集,而下游收集器又可以是分组或分区,以构建多级分组
- 在 Stream API 中,