java8学习之Collectors工厂类源码分析与实战

Wesley13
• 阅读 364

如上一节【http://www.cnblogs.com/webor2006/p/8360232.html】在结尾处谈到的,彻底理解了Collector收集器之后,有必要对其系统Collectors实现的各种非常常见的收集器进行仔细阅读,所以这也是接下来要去完成的,下面开始。

对于Collectors类而言,它是一个工厂类,因为它的构造是一个私的有,如下:

java8学习之Collectors工厂类源码分析与实战

而对于这个类中有一个静态类去实现Collector接口,这个也已经在之前详细分析过了,如下:

java8学习之Collectors工厂类源码分析与实战

而对于它里面的各种实现基本可以分为两种情况:

1、通过CollectorImpl来实现,如:

java8学习之Collectors工厂类源码分析与实战

2、通过reducing方法来实现,而reducting方法本身又是通过CollectorImpl来实现的,也就是说CollectorImpl是核心,如:

java8学习之Collectors工厂类源码分析与实战

下面则开始一个个具体方法分析:

Collectors.toList():

这个是咱们使用最多的一个方法啦,其实现也比较容易搞懂(前提是自己对收集器原理理解得非常透彻了),下面看一下:

java8学习之Collectors工厂类源码分析与实战

而其实上面的这种强制转换的方式还可以写成它:ArrayList::new。

接着第二个参数是“BiConsumer<A, T> accumulator”累加器,而该方法的实现如下:

java8学习之Collectors工厂类源码分析与实战

而第三个参数是“BinaryOperator combiner”,将多个结果容器合并成一个,实现如下:

java8学习之Collectors工厂类源码分析与实战

最后一个参数为:“Set characteristics”,也就是收集器的特性,这里实现是直接传的一个常量,如下:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

Collectors.toCollection():

对于toList()中间结果类型生成的就是ArrayList类型,如下:

java8学习之Collectors工厂类源码分析与实战

所以方法不需要任何参数,而想要换成其它的结果容器类型那么这个方法就派上用场啦,它是一个更加通用的方法, 当然具体的容器类型可以由咱们调用方来指定了,如下:

java8学习之Collectors工厂类源码分析与实战

所以此时对于收集器的第一个参数直接就传的是咱们进来的这个参数了:

java8学习之Collectors工厂类源码分析与实战

其它的参数其本上跟toList()实现类似,所以就不啰嗦啦,真的是如果知道了如何自己来自定义一个收集器,对于这些系统的实现看着是非常之亲切的。

Collectors.toSet():

基本上跟toList()的实现类似,第一个参数实例化结果容器,这里传的是HashSet,如下:

java8学习之Collectors工厂类源码分析与实战

第二个参数如下:

java8学习之Collectors工厂类源码分析与实战

第三个参数跟上面的方法实现一样,不多解释了,最后看一下第四个特性参数,这次的跟上面两个方法不一样了,下面看下:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

Collectors.joining():

该方法的作用是将集合中的元素进行字符串连接,之前也用它做过一些例子,下面看下它的具体实现:

首先看一下传的泛型类型:

java8学习之Collectors工厂类源码分析与实战

可以看到中间结果类型和最终结果类型是不一样的,所以可以看到它实际上是调用CollectorImpl类带有五个参数的构造函数,如下:

java8学习之Collectors工厂类源码分析与实战

相比上面的方法,多了一个finisher参数,为什么?因为中间结果类型跟最终结果类型不是同一个类型,所以需要通过调用finisher()方法对其进行类型转换嘛,好了,下面具体看一下参数是如何生成的:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

最后参数这次的特性又不同了,分析下:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

 接下来joining()还有以下两个方法重载,其中第二个joining()是调用最后一个joining方法来实现的,如下:

java8学习之Collectors工厂类源码分析与实战

所以将注意力就集中到最后一个joining()方法之上喽:

第一个参数实始化一个中间结果容器,这里采用了一个在Java1.8中提供的一个辅助类StringJoiner,它主要是用于字符串拼接的,如下:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

第二个参数为累加器,如下:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

第三个参数为中间结果合并:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

第四个参数则是生成结果,如下:

java8学习之Collectors工厂类源码分析与实战

最后一个特性也是无特性:

java8学习之Collectors工厂类源码分析与实战

Collectors.mapping():

下面先来看一下该方法的javadoc对它的说明:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

那啥叫"downstream"呢?可以瞅一下mapping()函数的方法定义:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

下面来看一下它的具体实现:除了第二个参数不一样之外,其它参数都是使用的downstream的相应的方法,如下:

java8学习之Collectors工厂类源码分析与实战

而焦点就定格到了第二个参数:元素累加器,也是mapping()实现的核心,其实也是用的下流的收集器做了一定的转换,下面具体来分析一下是如何达到转换的目的的:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

所以在javadoc上对应于这句话:

java8学习之Collectors工厂类源码分析与实战

Collectors.collectingAndThen():

先看一下它的javadoc:

java8学习之Collectors工厂类源码分析与实战

接下来看一下它的具体实现:

java8学习之Collectors工厂类源码分析与实战

 java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

也就是这个整个判断语句就是将"IDENTITY_FINISH"的特性去掉了,那为啥要去掉这个特性呢?其实很容易想到,因为该函数是必须要执行finisher()方法的,而如果设置有"IDENTITY_FINISH"特性则不会执行这个finisher()方法了。所以再看下面的返回:

java8学习之Collectors工厂类源码分析与实战

而andThen()就是Function里面提供的方法,这个咱们之前也已经学习过了,如下:

java8学习之Collectors工厂类源码分析与实战

Collectors.counting():

java8学习之Collectors工厂类源码分析与实战

而这里粗略的看一下reducing()方法的参数:

java8学习之Collectors工厂类源码分析与实战

根据传给reducing()方法的值,第一个参数为初始值为0;第二个参数则是将无素都转换成1,第三个则是进行元素的累加,因为所有元素值都变为1了,那总和既为元素的总个数。关于reducing()的具体实现分析放到下一次,这里有个初步印象既可。

Collectors.minBy()&Collectors.maxBy():

java8学习之Collectors工厂类源码分析与实战

Collectors.summingInt():

这个收集器是用来对元素进行求和用的,下面来看一下它的具体实现:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

实现是比较容易读懂的,但是有个疑问:为啥要生成一个长度为1的数组呢?最终不就是需要一个int的结果,直接生成一个int类型不就可以了,因为第一个参数是需要一个可变的结果容器,而单纯一个数字当然不是一个容器啦,另外数字是没法传递的,因为它是不可变的,所以这就是为啥要生成一个长度为1的数组的原因了。

类似的还有summingLong()、summingDouble(),这里就不再多说了。

Collectors.averagingInt():

这个是用来求平均值的,而平均值很显然是用总数除以个数,所以看一下它的实现:

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

java8学习之Collectors工厂类源码分析与实战

其中类似的还有averagingLong()、averagingDouble(),这里也不多说了。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
P2P技术揭秘.P2P网络技术原理与典型系统开发
Modular.Java(2009.06)\.Craig.Walls.文字版.pdf:http://www.t00y.com/file/59501950(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.t00y.com%2Ffile%2F59501950)\More.E
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这