java steam源码分析

前言

开发中喜欢使用stream的模式去处理数据流,因为其结合lambda让代码更加简洁,Stream的数据处理函数名也让代码的逻辑一目了然。

抽象模型介绍

Stream

stream接口是数据流转各节点的抽象,下面是stream的部分方法

public interface Stream<T> extends BaseStream<T, Stream<T>> {

    Stream<T> filter(Predicate<? super T> predicate);
    
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    
    IntStream mapToInt(ToIntFunction<? super T> mapper);
    
    ...
    
}    
 

常用实现类,这里以ReferencePipeline为例。下面是类图。
在这里插入图片描述
可以看到ReferencePipeline有三个实现类,下面一一解释:

Head

第一次创建Stream时默认是Head。

StatefulOp

有状态的Stream。主要是在并发执行的时候需要考虑状态问题。比如sort操作,需要收集到完整的集合才能进行排序。

        @Override
        final boolean opIsStateful() {
            return true;
        }
StatelessOp

无状态的Stream。不需要记录数据状态,可以处理完当前数据继续处理下一条数据。

        @Override
        final boolean opIsStateful() {
            return false;
        }

Sink

sink接口是对数据流操作控制的抽象,sink的主要方法

interface Sink<T> extends Consumer<T> {

    // 将集合的size向终点传递
    default void begin(long size) {}
    
    // lambda处理逻辑
    void accept(T t);
    
    // 所有数据处理结束后调用
    default void end() {}
}

主要实现类TerminalSink,ChainedReference
在这里插入图片描述

例子

下面以一个简单的例子来说明stream内部是如何运转

        List<Integer> list = Arrays.asList(1,2,3,4,5,6);
        list.stream().filter(i->i>2).forEach(System.out::println);

首先需要创建一个stream对象,就是上面提到的实现了Stream接口的Head

default Stream<E> stream() {
        // spliterator()获取一个迭代器,false表示非并发处理
        return StreamSupport.stream(spliterator(), false);
    }
    public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
        Objects.requireNonNull(spliterator);
        // 实例化一个Head对象
        return new ReferencePipeline.Head<>(spliterator,
                                            StreamOpFlag.fromCharacteristics(spliterator),
                                            parallel);
    }

Head对象实例化完成之后,就开始调用stream的filter实现,这里并没有立刻对数据进行任何操作。而是返回一个新的stream实现类对象。因为filter是一个无状态的操作,所以返回的是StatelessOp对象。StatelessOp重写了父类的opWrapSink方法,该方法会在数据返回一个sink实现类。可以看到Sink才是真正干活的类。那么opWrapSink会在哪调用呢,这个在后面会有详细介绍。

扫描二维码关注公众号,回复: 4134755 查看本文章
    @Override
    public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
        Objects.requireNonNull(predicate);
        // 将自身的引用作为参数传递到下一个stream
        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) {
                        // 对数据进行check,将符合条件的传递给下游节点
                        if (predicate.test(u))
                            downstream.accept(u);
                    }
                };
            }
        };
    }

继续到新的stream的foreach方法,因为foreach是一个terminal操作,所以不会再再返回stream对象,而是触发对数据的处理行为。

    @Override
    public void forEach(Consumer<? super P_OUT> action) {
            // makeRef会返回TerminalSink的实现类OfRef
            // 接着evaluate方法去执行数据的处理工作
            evaluate(ForEachOps.makeRef(action, false));
    }
        static final class OfRef<T> extends ForEachOp<T> {
            final Consumer<? super T> consumer;

            OfRef(Consumer<? super T> consumer, boolean ordered) {
                super(ordered);
                this.consumer = consumer;
            }

            @Override
            public void accept(T t) {
                consumer.accept(t);
            }
        }

evaluate会根据当前stream是否并发处理的状态来选择不同的处理行为

    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()));
    }

evaluateSequential会调用最后一个stream对象的wrapAndCopyInto,具体做了什么我们继续往下看

@Override
        public <S> Void evaluateSequential(PipelineHelper<T> helper,
                                           Spliterator<S> spliterator) {
            return helper.wrapAndCopyInto(this, spliterator).get();
        }

wrapSink会通过逆循环的方式找到流的第一个stream对象的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;
    }

走到这里我们就可以回答opWrapSink是如何使用的了,从当前节点依次向上查找自己的上一个节点,并通过调用opWrapSink方法来实例化各自的sink实现类,最后将第一个节点的sink对象返回,用于数据流的初始处理。

    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;
    }

这里拿到第一个节点即Head下面的Sink对象。并依次调用begin,accept,end方法。其中accept因为实在foreach里调用会被循环多次。因为我们例子里面的集合是ArrayList,所以这里的spliterator就是 ArrayListSpliterator

    @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);
            // 所有数据处理完成后再调用end方法
            wrappedSink.end();
        }
        else {
            copyIntoWithCancel(wrappedSink, spliterator);
        }
    }
public void forEachRemaining(Consumer<? super E> action) {
            int i, hi, mc; // hoist accesses and checks from loop
            ArrayList<E> lst; Object[] a;
            if (action == null)
                throw new NullPointerException();
            if ((lst = list) != null && (a = lst.elementData) != null) {
                if ((hi = fence) < 0) {
                    mc = lst.modCount;
                    hi = lst.size;
                }
                else
                    mc = expectedModCount;
                if ((i = index) >= 0 && (index = hi) <= a.length) {
                    for (; i < hi; ++i) {
                        @SuppressWarnings("unchecked") E e = (E) a[i];
                        // 集合里的元素每个都通过accept方法向下游传递,实现数据的流化
                        action.accept(e);
                    }
                    if (lst.modCount == mc)
                        return;
                }
            }
            throw new ConcurrentModificationException();
        }

刚才看的是无状态的stream,那么有状态的stream是如何处理数据的呢?下面以sort为例:

    @Override
    public final Stream<P_OUT> sorted() {
        return SortedOps.makeRef(this);
    }

创建OfRef对象,其是StatefulOp的子类

    static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream) {
        return new OfRef<>(upstream);
    }
        @Override
        public Sink<T> opWrapSink(int flags, Sink<T> sink) {
            Objects.requireNonNull(sink);

            // If the input is already naturally sorted and this operation
            // also naturally sorted then this is a no-op
            if (StreamOpFlag.SORTED.isKnown(flags) && isNaturalSort)
                return sink;
            else if (StreamOpFlag.SIZED.isKnown(flags))
                return new SizedRefSortingSink<>(sink, comparator);
            else
                return new RefSortingSink<>(sink, comparator);
        }

核心的逻辑在这里,当accept方法接收到数据后,并不是传递给下游的sink(对比filter的sink实现),而是将接收到的数据先暂存到一个list里面,相当于数据流在这里被阻断了,知道end方法被调用的时候,才开始对list数据做排序处理,处理结束后再将数据分发给下游sink,重新启动流。

    private static final class RefSortingSink<T> extends AbstractRefSortingSink<T> {
        private ArrayList<T> list;

        RefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
            super(sink, comparator);
        }

        @Override
        public void begin(long size) {
            if (size >= Nodes.MAX_ARRAY_SIZE)
                throw new IllegalArgumentException(Nodes.BAD_SIZE);
            list = (size >= 0) ? new ArrayList<T>((int) size) : new ArrayList<T>();
        }

        @Override
        public void end() {
            list.sort(comparator);
            downstream.begin(list.size());
            if (!cancellationWasRequested) {
                list.forEach(downstream::accept);
            }
            else {
                for (T t : list) {
                    if (downstream.cancellationRequested()) break;
                    downstream.accept(t);
                }
            }
            downstream.end();
            list = null;
        }

        @Override
        public void accept(T t) {
            list.add(t);
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_36031640/article/details/84112644
今日推荐