初识Collector
先看一个简单的场景:
现有集团内所有人员列表,需要从中筛选出上海子公司的全部人员
假定人员信息数据如下:
姓名 | 子公司 | 部门 | 年龄 | 工资 |
---|---|---|---|---|
大壮 | 上海公司 | 研发一部 | 28 | 3000 |
二牛 | 上海公司 | 研发一部 | 24 | 2000 |
铁柱 | 上海公司 | 研发二部 | 34 | 5000 |
翠花 | 南京公司 | 测试一部 | 27 | 3000 |
玲玲 | 南京公司 | 测试二部 | 31 | 4000 |
如果你曾经用过Stream流,或者你看过我前面关于Stream用法介绍的文章,那么借助Stream可以很轻松的实现上述诉求:
public void filterEmployeesByCompany() {
List<Employee> employees = getAllEmployees().stream()
.filter(employee -> "上海公司".equals(employee.getSubCompany()))
.collect(Collectors.toList());
System.out.println(employees);
}
上述代码中,先创建流,然后通过一系列中间流操作(filter
方法)进行业务层面的处理,然后经由终止操作(collect
方法)将处理后的结果输出为List对象。
但我们实际面对的需求场景中,往往会有一些更复杂的诉求,比如说:
现有集团内所有人员列表,需要从中筛选出上海子公司的全部人员,并按照部门进行分组
其实也就是加了个新的分组诉求,那就是先按照前面的代码实现逻辑基础上,再对结果进行分组处理就好咯:
public void filterEmployeesThenGroup() {
// 先 筛选
List<Employee> employees = getAllEmployees().stream()
.filter(employee -> "上海公司".equals(employee.getSubCompany()))
.collect(Collectors.toList());
// 再 分组
Map<String, List<Employee>> resultMap = new HashMap<>();
for (Employee employee : employees) {
List<Employee> groupList = resultMap
.computeIfAbsent(employee.getDepartment(), k -> new ArrayList<>());
groupList.add(employee);
}
System.out.println(resultMap);
}
似乎也没啥毛病,相信很多同学实际编码中也是这么处理的。但其实我们也可以使用Stream操作直接完成:
public void filterEmployeesThenGroupByStream() {
Map<String, List<Employee>> resultMap = getAllEmployees().stream()
.filter(employee -> "上海公司".equals(employee.getSubCompany()))
.collect(Collectors.groupingBy(Employee::getDepartment));
System.out.println(resultMap);
}
两种写法都可以得到相同的结果:
{
研发二部=[Employee(subCompany=上海公司, department=研发二部, name=铁柱, age=34, salary=5000)],
研发一部=[Employee(subCompany=上海公司, department=研发一部, name=大壮, age=28, salary=3000), Employee(subCompany=上海公司, department=研发一部, name=二牛, age=24, salary=2000)]
}
上述2种写法相比而言,第二种是不是代码上要简洁很多?而且是不是有种自注释的味道了?
通过collect方法的合理恰当利用,可以让Stream适应更多实际的使用场景,大大的提升我们的开发编码效率。下面就一起来全面认识下collect、解锁更多高级操作吧。
collect\Collector\Collectors区别与关联
刚接触Stream收集器的时候,很多同学都会被collect
,Collector
,Collectors
这几个概念搞的晕头转向,甚至还有很多人即使已经使用Stream好多年,也只是知道collect里面需要传入类似Collectors.toList()
这种简单的用法,对其背后的细节也不甚了解。
这里以一个collect收集器最简单的使用场景来剖析说明下其中的关系:
概括来说:
1️collect
是Stream流的一个 终止方法,会使用传入的收集器(入参)对结果执行相关的操作,这个收集器必须是Collector接口的某个具体实现类
2️Collector
是一个 接口,collect方法的收集器是Collector接口的 具体实现类
3️Collectors
是一个 工具类,提供了很多的静态工厂方法, 提供了很多Collector接口的具体实现类,是为了方便程序员使用而预置的一些较为通用的收集器(如果不使用Collectors类,而是自己去实现Collector接口,也可以)。
Collector使用与剖析
到这里我们可以看出,Stream结果收集操作的本质,其实就是将Stream中的元素通过收集器定义的函数处理逻辑进行加工,然后输出加工后的结果。
根据其执行的操作类型来划