jdk8,Stream流水线源码解析

我们通过一个示例,进行源码解析:如下:

Arrays.asList("a", "b", "c").stream().filter(e -> !e.equals("B")).skip(2).forEach(e -> System.out.println(e));
首先看stream()方法,它是用了Collection的stream()方法:

    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }

里面传进去了一个spliterator()函数,它是一个集合的迭代器,在ArrayList中有其具体实现。我们往下看:
    public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
        Objects.requireNonNull(spliterator);
        return new ReferencePipeline.Head<>(spliterator,
                                            StreamOpFlag.fromCharacteristics(spliterator),
                                            parallel);
    }

通过stream()方法生成了一个ReferecePipeline.Head对象,他是ReferencePipeline的子类,而ReferencePipeline是Stream的一个子类,所以我们通过这种方式就生成了一个Stream类。下面filter()方法:

    public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
        Objects.requireNonNull(predicate);
        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SIZED) {
            @Override
            Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
                    @Override
                    public void begin(long size) {
                        downstream.begin(-1);
                    }

                    @Override
                    public void accept(P_OUT u) {
                        if (predicate.test(u))
                            downstream.accept(u);
                    }
                };
            }
        };
    }

filter()方法中,返回了一个StatelessOp对象,它实现了一个方法opWrapSink,说明这是一个无状态的返回。这个方法中,有begin,accept方法,我们可以看到在accept方法中,它做了过滤处理,同时最后返回了一个Sink类的实例。在opWrapSink方法中,返回了sink类,sink类有四个实现方法,如下:begin(),accept(),end(),

cancellationRequested(),这四个实现类是流水线操作的核心,我们后面讲。
下面是skip方法:
public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
                                        long skip, long limit) {
        if (skip < 0)
            throw new IllegalArgumentException("Skip must be non-negative: " + skip);

        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
                                                      flags(limit)) {
            Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
                                                         long skip, long limit, long sizeIfKnown) {
                if (skip <= sizeIfKnown) {
                    // Use just the limit if the number of elements
                    // to skip is <= the known pipeline size
                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
                    skip = 0;
                }
                return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
            }

skip方法是返回的ReferencePipeline.StatefulOp,这是一个有状态的返回,有两个实现方法我们看下:

@Override
            <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
                                              Spliterator<P_IN> spliterator,
                                              IntFunction<T[]> generator) {
                long size = helper.exactOutputSizeIfKnown(spliterator);
                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
                    // Because the pipeline is SIZED the slice spliterator
                    // can be created from the source, this requires matching
                    // to shape of the source, and is potentially more efficient
                    // than creating the slice spliterator from the pipeline
                    // wrapping spliterator
                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
                    return Nodes.collect(helper, s, true, generator);

在这个方法中,做了一次集合的收集,关于哪里调用,我们稍后分析,】。

它也实现了opWrapSink方法:

@Override
            Sink<T> opWrapSink(int flags, Sink<T> sink) {
                return new Sink.ChainedReference<T, T>(sink) {
                    long n = skip;
                    long m = limit >= 0 ? limit : Long.MAX_VALUE;

                    @Override
                    public void begin(long size) {
                        downstream.begin(calcSize(size, skip, m));
                    }

                    @Override
                    public void accept(T t) {
                        if (n == 0) {
                            if (m > 0) {
                                m--;
                                downstream.accept(t);
                            }
                        }
                        else {
                            n--;
                        }
                    }

                    @Override
                    public boolean cancellationRequested() {
                        return m == 0 || downstream.cancellationRequested();
                    }
                };
            }
不过它实现的是begin,accept,和cancellationRequested()。

我们看到他们都会实现Sink的begin(),accept(),end(),cancellationRequested()中的一个或多个方法,这个就是流水线的核心,上面加粗的地方有个downstream就是下一个stream执行的方法,Steam就是按照这种方式,先顺序执行所有的begin(),然后所有accept(),然后所有end(),然后所有的cancellationRequested()方法。那么是哪一步发动的呢,就是这句话:

forEach(e -> System.out.println(e))
在最后收集结果的时候进行所有的处理,如下:
    @Override
    public void forEach(Consumer<? super P_OUT> action) {
        evaluate(ForEachOps.makeRef(action, false));
    }
在ReferencePipiline的forEach方法中传递了一个函数表达式,然后我们下看:
    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()));
    }

在AbstractPipeline中,y因为我们选的模式是非并行的所以进入第二个方法(加黑):
        @Override
        public <S> Void evaluateSequential(PipelineHelper<T> helper,
                                           Spliterator<S> spliterator) {
            return helper.wrapAndCopyInto(this, spliterator).get();
        }

这之后进入了ForEachOps的evaluateSequential()方法,helper参数就是我们的ReferencePipeline,也是我前面返回的Sink。
    @Override
    final <P_IN, S extends Sink<E_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator) {
        copyInto(wrapSink(Objects.requireNonNull(sink)), spliterator);
        return sink;
    }

在wrapSink方法中,就执行了我们前面说的onWrapSink方法,进去看下(注意:此时只是new Sink,并没有执行还没有执行begin(),accept()等方法,这些方法在copyInto中执行):
    @Override()
    @SuppressWarnings("unchecked")
    final <P_IN> Sink<P_IN> wrapSink(Sink<E_OUT> sink) {
        Objects.requireNonNull(sink);

        for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
            sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
        }
        return (Sink<P_IN>) sink;
    }
在for循环中,通过AbstractPipeline的depth参数判断还没有下一个,这个depth参数是,在开始生成Sink类的时候,就会让前面Sink的depth加1,
下面我们看下copyInto方法:
   @Override
    final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
        Objects.requireNonNull(wrappedSink);

        if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
            wrappedSink.begin(spliterator.getExactSizeIfKnown());
            spliterator.forEachRemaining(wrappedSink);
            wrappedSink.end();
        }
 
在这里执行了begin(),forEachRemaining中执行了accept,end()方法。到此,整个流程就结束了。此时,我们是不是有些疑问,如果我们执行sorted后,再执行skip,那么
它怎么能做到skip拦截掉的是排序后的前两个呢,这个就是设计的精妙处,我们看下sorted()方法的onWrapSink方法如下:
public void begin(long size) {
            if (size >= Nodes.MAX_ARRAY_SIZE)
                throw new IllegalArgumentException(Nodes.BAD_SIZE);
            array = (T[]) new Object[(int) size];
        }

        @Override
        public void end() {
            Arrays.sort(array, 0, offset, comparator);
            downstream.begin(offset);
            if (!cancellationWasRequested) {
                for (int i = 0; i < offset; i++)
                    downstream.accept(array[i]);
            }
            else {
                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
                    downstream.accept(array[i]);
            }
            downstream.end();
            array = null;
        }

        @Override
        public void accept(T t) {
            array[offset++] = t;
        }

我们发现,它在begin()中创建了一个数组,在accept中接收参数,在end中去做了排序,然后再执行downstream的accept()方法。这样就完美解决了,排序后在执行后续操作
的问题。
 
这就是Stream流水线的流程,这是最基本的,但所有的方法都是大同小异,有想研究别的方法的也可以按照此流程研究。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值