上篇是将符合条件的流元素加工后打印出来,这篇讲述如何收集起来。与上篇相比只有最后一个方法不一样
List<String> names= Arrays.asList("one", "two", "three", "four");
List<String> result = names.stream()
.filter(s -> s.length() > 2)
.map(String::toUpperCase)
.collect(Collectors.toList());
Collectors是个工具类,里面有多种方法来实现Collector这个接口:像本例中的Collectors.toList()。
Collectors.java
//CH_ID 表示流的特性是Collector.Characteristics.IDENTITY_FINISH
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },CH_ID);
}
Collector接口提供四个函数,相互配合将输入的条目累加到可变容器中,还能对容器中的结果来一个转化后返回,如果对函数式接口不熟悉,可以参考这篇。
Collector.java
/**
*Collector<T, A, R> 泛型接口
* T 元素类型 本例是String
* A 归并操作中可累积类型 本例是ArrayList
* R 归并结束后最终返回类型 本例与A一样
*/
//从名称看就是一个提供者
Supplier<A> supplier();
//从Consumer(消费者)延伸而来,Bi表示两,BiConsumer表示消费两个参数:一个是类型A,一个是类型T 。
BiConsumer<A, T> accumulator();
//相当于BiFunction<T,T,T> 即参数类型和返回类型一样
BinaryOperator<A> combiner();
//Function 表示消费A输出R,也就是对结果转化。本例返回类型R和A一样
Function<A, R> finisher();
CollectorImpl是Collectors的内部类,实现了Collector接口,比较简单,就是用参数初始化了字段,并提供方法获取
Collectors.java
static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A,R> finisher,
Set<Characteristics> characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
this.combiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
//本例使用这个构造方法,如上所说返回类型R和容器类型A一样,因为是泛型,用castingIdentity()方法强转了一下
CollectorImpl(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
...
}
再看collect方法的调用,它是在map方法返回的stream2上调用的
ReferencePipeline.java
public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
A container;
if (...) {
...
}
else {
//我们是串行流 走这个
container = evaluate(ReduceOps.makeRef(collector));
}
return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
? (R) container //构造Collector已设置其特性就是IDENTITY_FINISH,所以返回这个
: collector.finisher().apply(container);
}
ReduceOps也是一个工具类,这里使用上面的Collector作为参数,创建终结操作的实例
ReduceOps.java
public static <T, I> TerminalOp<T, I> makeRef(Collector<? super T, I, ?> collector) {
Supplier<I> supplier = Objects.requireNonNull(collector).supplier();
BiConsumer<I, ? super T> accumulator = collector.accumulator();
BinaryOperator<I> combiner = collector.combiner();
class ReducingSink extends Box<I> implements AccumulatingSink<T, I, ReducingSink> {
@Override
public void begin(long size) {
state = supplier.get();
}
@Override
public void accept(T t) {
accumulator.accept(state, t);
}
@Override
public void combine(ReducingSink other) {
state = combiner.apply(state, other.state);
}
}
return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) {
@Override
//ReduceOp的evaluateSequential方法会调用
public ReducingSink makeSink() {
return new ReducingSink();
}
...
};
}
先看返回值ReduceOp,它是ReduceOps内部抽象类,实现了TerminalOp。此处返回的是ReduceOp子类,它实现了makesink方法
ReduceOps.java
private static abstract class ReduceOp<T, R, S extends AccumulatingSink<T, R, S>>
implements TerminalOp<T, R> {
private final StreamShape inputShape;
...
//重要的抽象方法
public abstract S makeSink();
...
@Override
public <P_IN> R evaluateSequential(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
//makeSink()返回ReducingSink
//和前文一样,helper.wrapAndCopyInto(makeSink(), spliterator)返回makeSink的返回值,即ReducingSink
// ReducingSink的get方法返回的是ReducingSink中的state,在begin方法中初始化
return helper.wrapAndCopyInto(makeSink(), spliterator).get();
}
...
}
后面的流程和前一篇类似。ReducingSink的accept实现了收集操作
@Override
public void accept(T t) {
accumulator.accept(state, t);
}
流遍历结束以后,就会返回ReducingSink中的state,再回顾collect方法
ReferencePipeline.java
public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
A container;
if (...) {
...
}
else {
//返回的是collector中supplier提供 的内容
container = evaluate(ReduceOps.makeRef(collector));
}
return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
? (R) container //构造Collector已设置其特性就是IDENTITY_FINISH,所以返回这个,返回类型和容器类型一致
: collector.finisher().apply(container);
}
全部流程