Collector – JavaDoc
- 一个可变的规约操作,将输入元素累积到一个可变的输出结果容器中。
- 它会在所有元素处理完毕后,将累积的结果转换成为一个最终的表示。(可选操作)
- 可以串行/并行。
- Collectors本身提供了关于Collector的常见汇聚实现,Collectors本身实际上是一个工厂。
- Collector由4个函数构成,
|---Supplier<A> supplier创建并返回一个新的可变结果容器。
|---BiConsumer<A,T> accumulator 将一个新的数据元素合并到结果容器。
|---BinaryOperator<T> combiner 并发的
|---Function<A,R> finisher 将中间结果转换成最终表示(可选操作)
- 串行与并行结果的等价性,得满足以下两个条件
|--- identity (同一性)a==combiner.apply(a, supplier.get())
也就是说(List<T> list1,List<T>list2)->{list1.add(list2);return list1
|--- associativity(结合性) 要求r1==r2,文档代码如下
* A a1 = supplier.get();
* accumulator.accept(a1, t1);
* accumulator.accept(a1, t2);
* R r1 = finisher.apply(a1); // result without splitting
*
* A a2 = supplier.get();
* accumulator.accept(a2, t1);
* A a3 = supplier.get();
* accumulator.accept(a3, t2);
* R r2 = finisher.apply(combiner.apply(a2, a3));
关于是否使用Finisher函数
取决于你定义的Collector中的Characteristic中是否有FINISH的enum,当你设置这个enum时,你要确保A->R是成功的。这个强转发生在下图中的调用是否包含FINISH枚举的时候。
而Characteristic的调用是在Stream的实现类
ReferencePipeLine中的collect方法里。
代码如下:
如图,我们可以看到Collector中声明的三个枚举类的作用。
而并行和串行的调用取决于
而CONCURRENT这个枚举,在并行流中,代表了多个线程共同调用一个结果容器,则combine方法不需要被调用,如果不包含这个特性,则并行流的每一个线程就都会创建一个结果容器,然后进行combine。
这里可能会在add时报出一个异常
而这个异常抛出的时机是当你在迭代一个对象时候再修改他。通常这是不允许的。
同样的,当你使用CONCURRENT枚举时,你的中间容器也只会建立一个。