Stream的操作
中间操作
map()
返回一个流,当中包含了将给定函数应用到当前流中的每一个元素后返回的结果。
只有一种实现,在 ReferencePipeline 中定义
创建一个 StatelessOp(ReferencePipeline 的内部类),重写 opWrapSink(定义在 AbstractPipeline 中) 方法后返回
opWrapSink 方法创建 Sink.ChainedReference,重写 accept 方法,并返回
public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) { Objects.requireNonNull(mapper); return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { @Override Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) { return new Sink.ChainedReference<P_OUT, R>(sink) { @Override public void accept(P_OUT u) { downstream.accept(mapper.apply(u)); } }; } }; }
终止操作
forEach()
此操作的行为是非确定的;对于并行流,此操作并不会遵循遇到的元素的顺序,否则,将会牺牲掉并行的优势;对于任意的元素,此动作可能会在任意的时间、库提供的任意的线程中执行;若此动作访问了共享的状态,则需要提供必要的同步机制
实现
1. ReferencePipeline.Head.forEach()
当stream()与forEach()之间无中间操作时,由于 stream() 构建时,创建的是 ReferencePipeline.Head,并且重写了 forEach 方法,因此调用的是 ReferencePipeline.Head 中的方法,直接对源进行遍历(出于效率上的考量)
@Override public void forEach(Consumer<? super E_OUT> action) { if (!isParallel()) { sourceStageSpliterator().forEachRemaining(action); } else { super.forEach(action); } }
以非并行为例
调用的是 Spliterator 接口的 tryAdvance 方法
通过 while 循环不断执行 tryAdvance 方法,直至遍历完成返回 false
相当于将 Iterator 的 hasNext() 与 next() 方法合并
default void forEachRemaining(Consumer<? super T> action) { do { } while (tryAdvance(action)); }
tryAdvance有众多实现类,以 ArrayList 中的 ArrayListSpliterator 中的实现为例
将 Spliterator 中的下一个元素取出后,执行 action.accept();若到达结尾处,返回false
private int getFence() { // initialize fence to size on first use
int hi; // (a specialized variant appears in method forEach)
ArrayList<E> lst;
if ((hi = fence) < 0) {
if ((lst = list) == null)
hi = fence = 0;
else {
expectedModCount = lst.modCount;
hi = fence = lst.size;
}
}
return hi;
}
public boolean tryAdvance(Consumer<? super E> action) { if (action == null) throw new NullPointerException(); int hi = getFence(), i = index; if (i < hi) { index = i + 1; @SuppressWarnings("unchecked") E e = (E)list.elementData[i]; action.accept(e); if (list.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } return false; }
2. ReferencePipeline.forEach()
当存在中间操作时,每添加一个操作,都会创建一个 ReferencePipeline.StatelessOp 对象,由于 StatelessOp 没有重写 forEach 方法,因此,调用的是 ReferencePipeline 中的方法
@Override public void forEach(Consumer<? super P_OUT> action) { evaluate(ForEachOps.makeRef(action, false)); }
- ForEachOps.makeRef:构造一个 TerminalOp,传入的 action 将会作用于所有的元素
- 返回 ForEachOp.OfRef 类(ForEachOp 的内部类)
- TerminalOp 共有 4种 大的实现类:FindOp、ForEachOp、MatchOp、ReduceOp
final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) { assert getOutputShape() == terminalOp.inputShape(); if (linkedOrConsumed) throw new IllegalStateException(MSG_STREAM_LINKED); linkedOrConsumed = true; return isParallel() ? terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags())) : terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags())); }
sourceSpliterator()
-
若当前管道阶段为源阶段,则直接获取到源阶段的分割迭代器
-
此方法被调用并成功返回后,此管道就会被消费掉
sourceSpliterator(int terminalFlags)
- 获取到当前管道阶段的源 spliterator
-
对于串行的或无状态并行的管道,此 spliterator 即为 源spliterator
-
对于又状态的并行管道,此 spliterator 描述了所有计算一直往下进行的结果,并且包含了最近的有状态的操作
最后调用 terminalOP 的 evaluateParallel 或 evaluateSequential 方法并返回结果(ForEach不返回结果)