1.11 下游收集器
groupingBy方法会产生一个映射表,它的每个值都是一个列表。如果想要以某种方式来处理这些列表,就需要提供一个“下游收集器”。例如,如果想要获得集而不是列表,那么可以使用上一节中看到的Collector.toSet收集器:
注意:在本节的这个示例以及后续示例中,我们认为静态导入java.util.stream.Collectors.*会使表达式更容易阅读。
Java提供了多种可以将群组元素约简为数字的收集器:
·counting会产生收集到的元素的个数。例如:
可以对每个国家有多少个Locale进行计数。
·summing(Int|Long|Double)会接受一个函数作为引元,将该函数应用到下游元素中,并产生它们的和。例如:
可以计算城市流中每个州的人口总和。
·maxBy和minBy会接受一个比较器,并产生下游元素中的最大值和最小值。例如:
可以产生每个州中最大的城市。
mapping方法会产生将函数应用到下游结果上的收集器,并将函数值传递给另一个收集器。例如:
这里,我们按照州将城市群组在一起。在每个州内部,我们生成了各个城市的名字,并按照最大长度约简。
mapping方法还针对上一节中的问题,即把某国所有的语言收集到一个集中,产生了一种更佳的解决方案。
在上一节中,我们使用的是toMap而不是groupingBy。而在上述这种方式中,我们无须操心如何将各个集组合起来。
如果群组和映射函数的返回值为int、long或double,那么可以将元素收集到汇总统计对象中,就像1.8节中所讨论的一样。例如,
然后,可以从每个组的汇总统计对象中获取这些函数值的总和、个数、平均值、最小值和最大值。
注意:还有3个版本的reducing方法,它们都应用了通用的约简操作,正如1.12节中所描述的一样。
将收集器组合起来是一种很强大的方式,但是它也可能会导致产生非常复杂的表达式。它们的最佳用法是与groupingBy和partitioningBy一起处理“下游的”映射表中的值。否则,应该直接在流上应用诸如map、reduce、count、max或min这样的方法。
程序清单1-6中的示例程序演示了下游收集器。
程序清单1-6 collecting/DownstreamCollectors.java
java.util.stream.Collectors 8
·static<T>Collector<T,?,Long>counting()
产生一个可以对收集到的元素进行计数的收集器。
·static<T>Collector<T,?,Integer>summingInt(ToIntFunction<?super T>mapper)
·static<T>Collector<T,?,Long>summingLong(ToLongFunction<?super T>mapper)
·static<T>Collector<T,?,Double>summingDouble(ToDoubleFunction<?super T>mapper)
产生一个收集器,对将mapper应用到收集到的元素上之后产生的值计算总和。
·static<T>Collector<T,?,Optional<T>>maxBy(Comparator<?super T>comparator)
·static<T>Collector<T,?,Optional<T>>minBy(Comparator<?super T>comparator)
产生一个收集器,使用comparator指定的排序方法,计算收集到的元素中的最大值和最小值。
·static<T,U,A,R>Collector<T,?,R>mapping(Function<?super T,?extends U>mapper,Collector<?super U,A,R>downstream)
产生一个收集器,它会产生一个映射表,其键是将mapper应用到收集到的数据上而产生的,其值是使用downstream收集器收集到的具有相同键的元素。