概述
在JDK中对Collector的定义是一个可变的归约操作(A mutable reduction operation</a>)。是一种操作思想,分为计算元素、归集计算结果两个主要的步骤;为了保存计算元素的中间状态,所以会提供一个容器来完成中间状态和中间结果的保存。如下面的集合操作:
public class CollecorTest {
public static void main(String[] args) {
/**
* 对所有元素追击后缀“suffix”
* 再以map的形式输出,key和value都是元素本身
*/
List<String> list = Arrays.asList("hello","world","welcome","yes","no");
List<String> container = new ArrayList<>(); //创建一个中间容器,用来保存中间状态
for (String element : list) {
container.add(element+"suffix"); //对中间元素进行操作,并存入容器中
}
Map<String,String> map = new HashMap<String,String>();
for (String element : container) {
map.put(element,element); //再次操作改变集合的形式,归集结果
}
}
}
在Collector接口提供四个方法:
/**
* 1、 Supplier<A> supplier();--> 不接受参数,返回一个值。充当提供容器的角色
* 2、 BiConsumer<A, T> accumulator();--> 接收两个参数,不返回结果。其接收的两个参数,第一个是supplier提供的集合;第二个参数是待操作的元素,将元素操作完之后,放入集合中。
* 3、 BinaryOperator<A> combiner(); --> 这个方法主要是应对并发操作时,会出现多个中间容器,需要通过conbiner方法将多个中间结果容器进行合并,因为在finnish中只会接收一个参数。如果不需要合并,则不会执行conbiner方法
* 4、 Function<A, R> finishaer(); --> 接收一个参数,返回一个值。这是最后的归集操作,方法接收的参数就是accumulator或者是combiner产生的结果,也就是一个中间的结果集。中间结果集合通过finisher方法输出最终结果
*/
所以Collector只是规定一种元素运算方式,或者说是一种运算规范,具体的运算内容可以自定义。
Collector的创建
源代码:
public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A, R> finisher,
Characteristics... characteristics) {
Objects.requireNonNull(supplier);
Objects.requireNonNull(accumulator);
Objects.requireNonNull(combiner);
Objects.requireNonNull(finisher);
Objects.requireNonNull(characteristics);
Set<Characteristics> cs = Collectors.CH_NOID;
if (characteristics.length > 0) {
cs = EnumSet.noneOf(Characteristics.class);
Collections.addAll(cs, characteristics);
cs = Collections.unmodifiableSet(cs);
}
return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
}
of方法返回的是一个CollectorImpl类。CollectorImpl是Collector中的一个静态内部类。这样做的原因主要是使用者不需要自己去定义实现类,然后再进行创建,减少使用者的工作量,同时又能够使代码更简洁优雅。
Collector的构造函数接收5个参数,前面四个(supplier,accumulator,combiner,finisher),这四个参数分别对应上面介绍的四个方法。最后一个参数使用来控制Collector的执行方式的。
1、 CONCURRENT //将会以并行的方式进行操作
2、 UNORDERED //不保证输出结果的顺序(没理解)
3、 IDENTITY_FINISH //恒等函数,当传入这个值时,finisher函数将不会执行,而直接返回结果
IDENTITY_FINISH: 传入这个参数,finisher函数将会被认为是一个恒等函数。即:输出类型与输入类型完全一致。此时将不会再执行finisher方法,而是将中间结果集合进行强制类型转换得到最后的结果。源代码如下:
collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
? (R) container
:collector.finisher().apply(container)
CONCURRENT:
1、 传入这个参数,同时调用parallel()方法,supplier方法只会执行一次,并且会创建多个线程操作这个集合。
2、 不传入这个参数,同时调用parallel()方法,将会执行supplier()方法多次,创建多个线程操作多个容器。
3、 传入这个参数,不调用parallel()方法,supplier方法只会执行一次,不会创建多个线程,使用主线程执行操作。