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不返回结果)

posted @ 2019-09-17 23:27  飞蛇在水  阅读(278)  评论(0编辑  收藏  举报