![Java核心技术·卷Ⅱ:高级特性(原书第10版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/937/34339937/b_34339937.jpg)
1.11 下游收集器
groupingBy方法会产生一个映射表,它的每个值都是一个列表。如果想要以某种方式来处理这些列表,就需要提供一个“下游收集器”。例如,如果想要获得集而不是列表,那么可以使用上一节中看到的Collector.toSet收集器:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/024-i.jpg?sign=1739263052-f7VM168pLUP7lY97z4cK5auDF4fegx43-0-0641eaed35e1c4498a7361054e0e89bc)
注意:在本节的这个示例以及后续示例中,我们认为静态导入java.util.stream.Collectors.*会使表达式更容易阅读。
Java提供了多种可以将群组元素约简为数字的收集器:
·counting会产生收集到的元素的个数。例如:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/024-2-i.jpg?sign=1739263052-vHv3VPbzpiGoyZuJ7GyDNagw4dEnZbXb-0-a4158c5151bc0db006929f8754160e76)
可以对每个国家有多少个Locale进行计数。
·summing(Int|Long|Double)会接受一个函数作为引元,将该函数应用到下游元素中,并产生它们的和。例如:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/024-3-i.jpg?sign=1739263052-QAfgBb8rpUg0UaH4p9KajF6ee8OwRPB9-0-d06c87f63133116880e209d41f2735eb)
可以计算城市流中每个州的人口总和。
·maxBy和minBy会接受一个比较器,并产生下游元素中的最大值和最小值。例如:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/024-4-i.jpg?sign=1739263052-7yCe6q3cNUWfbsjmnpwz2MKi5b8U2Xkt-0-37b5e06ebd29ea0a02ee7846fefe6c36)
可以产生每个州中最大的城市。
mapping方法会产生将函数应用到下游结果上的收集器,并将函数值传递给另一个收集器。例如:
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/025-i.jpg?sign=1739263052-DEdKosx5IAEzdDuFarJ57kctacDfVGc3-0-30809e501ebdb319949ec805a24dcc29)
这里,我们按照州将城市群组在一起。在每个州内部,我们生成了各个城市的名字,并按照最大长度约简。
mapping方法还针对上一节中的问题,即把某国所有的语言收集到一个集中,产生了一种更佳的解决方案。
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/025-2-i.jpg?sign=1739263052-bOCs2Dw21fsxJvA9ZJVvYr54PxDTVP9x-0-8d72082874a6bb6bbcc073dd04f4bc88)
在上一节中,我们使用的是toMap而不是groupingBy。而在上述这种方式中,我们无须操心如何将各个集组合起来。
如果群组和映射函数的返回值为int、long或double,那么可以将元素收集到汇总统计对象中,就像1.8节中所讨论的一样。例如,
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/025-3-i.jpg?sign=1739263052-DlTSMuR0Puxda621mLc4rJdLkKPvaoSp-0-04d33dccc9b159ef100fc326c9f6165e)
然后,可以从每个组的汇总统计对象中获取这些函数值的总和、个数、平均值、最小值和最大值。
注意:还有3个版本的reducing方法,它们都应用了通用的约简操作,正如1.12节中所描述的一样。
将收集器组合起来是一种很强大的方式,但是它也可能会导致产生非常复杂的表达式。它们的最佳用法是与groupingBy和partitioningBy一起处理“下游的”映射表中的值。否则,应该直接在流上应用诸如map、reduce、count、max或min这样的方法。
程序清单1-6中的示例程序演示了下游收集器。
程序清单1-6 collecting/DownstreamCollectors.java
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/025-4-i.jpg?sign=1739263052-rpIvNl47hF4jGoOcClkrBU44zXCoJAJs-0-c0344e96301f59ee9f01f2c2239d5763)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/026-i.jpg?sign=1739263052-Tb3C8Nk4diDAbopgQtkmn34togfGZUWW-0-111552c81af737c521ddb9394a55fc90)
![](https://epubservercos.yuewen.com/F21227/18365861501241106/epubprivate/OEBPS/Images/027-i.jpg?sign=1739263052-5TOUrnGNeKso7T6Oc7fUDiJOs3UMlvFw-0-1aaaab4505eccd8517a155e2e054da25)
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收集器收集到的具有相同键的元素。