Stream初解

Stream初解

1.对象引用流

在这里插入图片描述

  • BaseStream

BaseStream表示流的基本接口,流是支持顺序和并行聚合操作的元素序列

public interface BaseStream<T, S extends BaseStream<T, S>>
        extends AutoCloseable {
    /**
     * 返回此流的元素的迭代器。
	 * 这是一个 终端操作。
     */
    Iterator<T> iterator();

	/**
     * 返回此流的元素的拆分器。
	 * 这是一个 终端操作。
     */
    Spliterator<T> spliterator();

	/**
     * 此流是不是并行流
     */
    boolean isParallel();

    /**
     * 返回顺序的等效流。可能返回自身,因为流已经是顺序的,或者因为基础流状态被修改为顺序。
	 * 这是一个中间操作。
     */
    S sequential();

    /**
     * 返回并行的等效流。可能返回自身,因为流已经是并行的,或者因为基础流状态已修改为并行。
	 * 这是一个 中间操作。
     */
    S parallel();

    /**
     * 返回无序的等效流。可能会返回自身,因为流已无序,或者因为基础流状态已修改为无序。
	 * 这是一个 中间操作。
     */
    S unordered();

    /**
     * 返回具有其他关闭处理程序的等效流。关闭处理程序在流上调用方法 close() 时运行,并按添加顺序执行。
     * 所有关闭处理程序都会运行,即使早期的关闭处理程序会引发异常。
     * 如果任何关闭处理程序引发异常,则引发的第一个异常将中继给 的调用方 close(),
     * 并将任何剩余的异常作为抑制的异常添加到该异常中(除非剩余的异常之一与第一个异常相同,因为异常无法抑制自身。)
     * 可能会自行返回
     * 这是一个 中间操作。
     */
    S onClose(Runnable closeHandler);

    /**
     * Closes this stream, causing all close handlers for this stream pipeline
     * to be called.
     * 关闭此流,从而调用此流管道的所有关闭处理程序。
     * @see AutoCloseable#close()
     */
    @Override
    void close();
}
  • Stream

​ 继承BaseStream,支持顺序和并行聚合操作的元素序列。包含引用类型的终止和中间操作

​ 相似的还有DoubleStream、IntStream、LongStream。

  • PipelineHelper

​ 用于执行流管道的帮助程序类,在一个位置捕获有关流管道的所有信息(输出类型、中间操作、 流标志、并行度等)。

​ A PipelineHelper 描述了流管道的初始段,包括其源、中间操作,并且还可以包含有关终端(或有状态)操作的信息,该操作遵循本PipelineHelper描述的最后一个中间操作。TerminalOp.evaluateParallel(PipelineHelper, Spliterator)传递给 PipelineHelper 、 和 AbstractPipeline.opEvaluateParallel(PipelineHelper, Spliterator, IntFunction)、 方法,这些方法可以使用 来访问有关管道的信息(如头部类型、流标志和大小),并使用帮助程序方法(如 wrapAndCopyInto(Sink, Spliterator)、 TerminalOp.evaluateSequential(PipelineHelper, Spliterator)copyInto(Sink, Spliterator)和wrapSink(Sink))来PipelineHelper执行管道操作。

abstract class PipelineHelper<P_OUT> {

    返回流的类型
    abstract StreamShape getSourceShape();
    
    enum StreamShape {

    REFERENCE,

    INT_VALUE,

    LONG_VALUE,

    DOUBLE_VALUE
	}

    获取所述管道输出的组合流和操作标志。这将包含来自流源的流标志、所有中间操作和终端操作。
    abstract int getStreamAndOpFlags();

  	返回将 this PipelineHelper 描述的管道阶段应用于提供的 Spliterator描述的输入部分(如果已知)所产生的输出部分的确切输出大小。
    如果不知道或已知无限,将返回 -1.
    如果 Spliterator 具有该 SIZED 特征,则确切的输出大小是已知的,并且操作标志在组合的流和操作标志 StreamOpFlag.SIZED 上是已知的。    
    abstract<P_IN> long exactOutputSizeIfKnown(Spliterator<P_IN> spliterator);

 	//由终止操作间接调用,调用wrapSink方法构建Sink链表,调用copyInto方法完成数据操作
    abstract<P_IN, S extends Sink<P_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator);

    //将Spliterator中的元素提供给Sink消费
    abstract<P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator);

	//类似copyInto,区别在于这个方法用于短路操作
    abstract <P_IN> void copyIntoWithCancel(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator);

	//包装Sink形成Sink链
    abstract<P_IN> Sink<P_IN> wrapSink(Sink<P_OUT> sink);

    //包装拆分流
    abstract<P_IN> Spliterator<P_OUT> wrapSpliterator(Spliterator<P_IN> spliterator);

    /**
     * Constructs a @{link Node.Builder} compatible with the output shape of
     * this {@code PipelineHelper}.
     *
     * @param exactSizeIfKnown if >=0 then a builder will be created that has a
     *        fixed capacity of exactly sizeIfKnown elements; if < 0 then the
     *        builder has variable capacity.  A fixed capacity builder will fail
     *        if an element is added after the builder has reached capacity.
     * @param generator a factory function for array instances
     * @return a {@code Node.Builder} compatible with the output shape of this
     *         {@code PipelineHelper}
     */
    abstract Node.Builder<P_OUT> makeNodeBuilder(long exactSizeIfKnown,
                                                 IntFunction<P_OUT[]> generator);

	//并行流调用
    abstract<P_IN> Node<P_OUT> evaluate(Spliterator<P_IN> spliterator,
                                        boolean flatten,
                                        IntFunction<P_OUT[]> generator);
}

  • AbstractPipeline 继承PipelineHelper 并实现 BaseStream

​ “管道”类的抽象基类,这些类是 Stream 接口及其基元专用化的核心实现

​ 表示 AbstractPipeline 流管道的初始部分,封装流源和零个或多个中间操作。单个 AbstractPipeline 对象通常称为阶段,其中每个 阶段描述流源或中间操作。

​ 也是流中双向链表的结点

	//pipeline链表的头结点,如果当前节点就是头节点,那么将指向自己。
	private final AbstractPipeline sourceStage;

    //链表的上一个结点
    @SuppressWarnings("rawtypes")
    private final AbstractPipeline previousStage;

    //此管道对象表示的中间操作的操作标志。
    protected final int sourceOrOpFlags;

  	//链表的下一个结点
    @SuppressWarnings("rawtypes")
    private AbstractPipeline nextStage;

    //链表的深度、初始为0 每增加一个节点depth+1
    private int depth;

    //源和所有操作的组合源和操作标志,直到并包括此管道对象表示的操作。在准备评估的管道时有效。
    private int combinedFlags;

    //源拆分器
    private Spliterator<?> sourceSpliterator;

    //同sourceSpliterator
    private Supplier<? extends Spliterator<?>> sourceSupplier;

    //pipeline是否已经被连接或者消费
    private boolean linkedOrConsumed;

    //pipeline上是否有有状态的操作
    private boolean sourceAnyStateful;

    private Runnable sourceCloseAction;

    //是否是并行流
    private boolean parallel;
  • ReferencePipeline 引用类型的管道抽象类 继承了AbstractPipeline 实现了Stream

​ 包含了Head(ReferencePipeline 的源阶段)、StatelessOp(Stream 的无状态中间阶段的基类。)、StatefulOp(Stream 的有状态中间阶段的基类。)三个子类

2.操作

Stream 流操作可以分为 3 种类型:

  • 创建 Stream

  • Stream 中间处理

  • 终止 Steam

中间处理只是一种标记,只有终止操作才会触发实际计算。 中间操作又可以分为无状态的(Stateless)和有状态的(Stateful),无状态中间操作是指元素的处理不受前面元素的影响,而有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果; 结束操作又可以分为短路操作和非短路操作,短路操作是指不用处理全部元素就可以返回结果,比如 找到第一个满足条件的元素。之所以要进行如此精细的划分,是因为底层对每一种情况的处理方式不同。

在这里插入图片描述

2.1 创建 Stream

在这里插入图片描述

2.2 Stream 中间处理

在这里插入图片描述

2.3 终止 Steam

在这里插入图片描述

3.源码解析

        Stream.of("java", "scala", "go", "python")
                .map(String::length)
                .filter(len -> len <= 4)
                .forEach(System.out::println);

将四个元素创建为一个Stream并调用map获取长度、过滤长度小于等于四的元素最后进行打印

    public static<T> Stream<T> of(T... values) {
        //调用了Arrays里的方法
        return Arrays.stream(values);
    }

	public static <T> Stream<T> stream(T[] array) {
        //调用了一个重载方法
        return stream(array, 0, array.length);
    }
	
	//array – 数组,假定在使用过程中未被修改 
    //startInclusive – 第一个涵盖的指数,包括 
    //endExclusive – 紧接在最后一个要覆盖的索引之后的索引	
	public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
        //spliterator方法表示创建一个拆分器  
        return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
    }
	
	public static <T> Spliterator<T> spliterator(T[] array, int startInclusive, int endExclusive) {
        //additionalCharacteristics 拆分器的特性
        //Spliterator.ORDERED 表示为元素定义了遭遇顺序的特征值。如果是这样,则此 Spliterator 保证该方法拆分元素的严格前缀,该方法				             trySplittryAdvance按前缀顺序按一个元素步进,并forEachRemaining按遭遇顺序执行操作。
        //Spliterator.IMMUTABLE 表示元素源不能在结构上修改的特征值;也就是说,不能添加、替换或删除元素,因此在遍历过程中不会发生此类更改。
        return Spliterators.spliterator(array, startInclusive, endExclusive,
                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
    }

	//array – 数组,假定在使用过程中未被修改 
	//fromIndex – 要涵盖的最少指数(包括) 
	//toIndex – 一个过去最大的指数覆盖 
	//additionalCharacteristics– 始终报告此分路器源或元素的其他SIZEDSUBSIZED分路器特性	
	public static <T> Spliterator<T> spliterator(Object[] array, int fromIndex, int toIndex,
                                                 int additionalCharacteristics) {
        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
        //新建一个数组类型的拆分器(ArraySpliterator)   Spliterators的一个内部类
        return new ArraySpliterator<>(array, fromIndex, toIndex, additionalCharacteristics);
    }

	

接下来来看StreamSupport

用于创建和操作流的低级实用工具方法。
此类主要用于呈现数据结构的流视图的库编写器;大多数面向最终用户的静态流方法都位于各种 Stream 类中。

    //根据一个拆分流 和是否是并行流创建一个stream
	public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
        Objects.requireNonNull(spliterator);
        //Head是ReferencePipeline的一个内部类 表示流双向链表的头节点
        return new ReferencePipeline.Head<>(spliterator,
                                            StreamOpFlag.fromCharacteristics(spliterator),
                                            parallel);
    }
	//将设置的拆分器特征转换为流标志
	static int fromCharacteristics(Spliterator<?> spliterator) {
        int characteristics = spliterator.characteristics();
        if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) {
            // Do not propagate the SORTED characteristic if it does not correspond
            // to a natural sort order
            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED;
        }
        else {
            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
        }
    }

	//构造方法 
	Head(Spliterator<?> source,
             int sourceFlags, boolean parallel) {
            //调用了父方法 ReferencePipeline构造方法
            super(source, sourceFlags, parallel);
    }
	//构造方法
	ReferencePipeline(Spliterator<?> source,
                      int sourceFlags, boolean parallel) {
        //调用了父方法 AbstractPipeline构造方法
        super(source, sourceFlags, parallel);
    }
	//流管道头部的构造方法
	AbstractPipeline(Spliterator<?> source,
                     int sourceFlags, boolean parallel) {
        //头节点 流管道的上一个节点为null
        this.previousStage = null;
        //设置源拆分器
        this.sourceSpliterator = source;
        //设置管道链表头节点为自己
        this.sourceStage = this;
        this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
        // The following is an optimization of:
        // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
        this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
        //设置当前深度为0
        this.depth = 0;
        //设置是否是并行流
        this.parallel = parallel;
    }

Stream.of(“java”, “scala”, “go”, “python”) 操作最终将这四个元素转换为一个数组拆分器,并根据此拆分器实例化了一个流管道的头节点

如图
在这里插入图片描述
接下来看map操作

    @Override
    @SuppressWarnings("unchecked")
    public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
        Objects.requireNonNull(mapper);
        //创建了一个StatelessOp实例 StatelessOp是ReferencePipeline的内部类 无状态操作的基类
        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
            @Override
            //操作包装Sink
            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));
                    }
                };
            }
        };
    }
	//构造方法 upstream表示流管道的上一个节点 在此表示上一个Head节点
	StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
                    StreamShape inputShape,
                    int opFlags) {
        	//调用了父类的构造方法 ReferencePipeline构造方法
            super(upstream, opFlags);
            assert upstream.getOutputShape() == inputShape;
    }
	//构造方法
	ReferencePipeline(AbstractPipeline<?, P_IN, ?> upstream, int opFlags) {
        //调用了父方法 AbstractPipeline构造方法
        super(upstream, opFlags);
    }
	//用于将中间操作阶段追加到现有管道的构造函数 previousStage上一个流管道节点
	AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
        //上一个流管道节点是否被引用或消费
        if (previousStage.linkedOrConsumed)
            throw new IllegalStateException(MSG_STREAM_LINKED);
        //设置上一个流管道已经被引用
        previousStage.linkedOrConsumed = true;
        //上一个流管道的下一个节点为当前节点
        previousStage.nextStage = this;
		//设置当前节点的上一个节点
        this.previousStage = previousStage;
        this.sourceOrOpFlags = opFlags & StreamOpFlag.OP_MASK;
        this.combinedFlags = StreamOpFlag.combineOpFlags(opFlags, previousStage.combinedFlags);
        //设置当前流的头节点
        this.sourceStage = previousStage.sourceStage;
        if (opIsStateful())
            sourceStage.sourceAnyStateful = true;
        //设置深度
        this.depth = previousStage.depth + 1;
    }

.map(String::length) 是一个无状态的中间操作生成了一个StatelessOp实例
在这里插入图片描述
接下来看.filter(len -> len <= 4)

    //同样创建了一个无状态的StatelessOp实例
	@Override
    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);
                    }
                };
            }
        };
    }

在这里插入图片描述
.forEach(System.out::println) 该操作是一个终止操作 当前实例为 第三个节点 StatelessOp

    //调用ReferencePipeline中的foreach方法 一个终止操作 	
	@Override
    public void forEach(Consumer<? super P_OUT> action) {
        evaluate(ForEachOps.makeRef(action, false));
    }
	//ForEachOps的静态方法 返回一个终端操作 TerminalOp<E_IN, R> <E_IN> – 输入元素的类型 <R> – 结果的类型 
	// 流管道中的一种操作,该操作将流作为输入并产生结果或副作用。
	//A TerminalOp 具有输入类型和流形状,以及结果类型。inputShape() 默认为 StreamShape.REFERENCE; 
	//A TerminalOp 还具有一组操作标志,用于描述 操作 如何处理流的元素 getOpFlags() 默认为0
	//其中还包含执行并行流(evaluateParallel)和顺序流操作方法(evaluateSequential)
	//当前方法返回了ForEachOp中的一个内部类OfRef
	// static abstract class ForEachOp<T> implements TerminalOp<T, Void>, TerminalSink<T, Void>
	public static <T> TerminalOp<T, Void> makeRef(Consumer<? super T> action,
                                                  boolean ordered) {
        Objects.requireNonNull(action);
        return new ForEachOp.OfRef<>(action, ordered);
    }

	// TerminalSink为终止Sink 
	interface TerminalSink<T, R> extends Sink<T>, Supplier<R> { }
	//Sink用于在流管道的各个阶段执行值的扩展Consumer,以及用于管理大小信息、控制流等的其他方法。
	//接收器可能处于以下两种状态之一:初始状态和活动状态。它从初始状态开始;该 begin() 方法将其转换为活动状态,然后 end() 该方		法将其转换回初始状态,在该状态中可以重用它。数据接受方法(例如 accept() ,仅在活动状态下有效。
	// 其中有一个内部抽象类 引用类型的调用链表示
    static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
        //下一个管道流的Sink
        protected final Sink<? super E_OUT> downstream;

        public ChainedReference(Sink<? super E_OUT> downstream) {
            this.downstream = Objects.requireNonNull(downstream);
        }
		//重置接收器状态以接收新的数据集。在将任何数据发送到接收器之前,必须调用此函数。调用 后,可以调用 end()该方法重置接收器		  以进行其他计算。
		//参数:
		//size – 要推送到下游的数据的确切大小,如果已知或未知或 -1 无限。
		//在此调用之前,接收器必须处于初始状态,在此调用之后,它处于活动状态
        @Override
        public void begin(long size) {
            downstream.begin(size);
        }
		//指示已推送所有元素。如果是 Sink 有状态的,则此时应向下游发送任何存储状态,并应清除任何累积状态(和关联的资源)。
		//在此调用之前,接收器必须处于活动状态,在此调用之后,接收器将返回到初始状态。
        @Override
        public void end() {
            downstream.end();
        }
		//指示它 Sink 不希望再接收任何数据
        @Override
        public boolean cancellationRequested() {
            return downstream.cancellationRequested();
        }
    } 
	//引用类型的遍历操作表示 此例子中 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);
            }
    }

	//调用AbstractPipeline(第三个节点 StatelessOp )中的evaluate方法
	//terminalOp为ForEachOp.OfRef实例
	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(terminalOp.getOpFlags())
	
	//ForEachOp.OfRef实例 ForEachOpd实现的terminalOp方法 
   @Override
   public <S> Void evaluateSequential(PipelineHelper<T> helper,
                                           Spliterator<S> spliterator) {
            return helper.wrapAndCopyInto(this, spliterator).get();
   }
	//第三个节点 StatelessOp 实例 调用AbstractPipeline实现的PipelineHelper方法
	@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;
    }
	//第三个节点 StatelessOp 实例 调用AbstractPipeline实现的PipelineHelper方法
	//sink为ForEachOp.OfRef实例
	@Override
    @SuppressWarnings("unchecked")
    final <P_IN> Sink<P_IN> wrapSink(Sink<E_OUT> sink) {
        Objects.requireNonNull(sink);
        //遍历(从后往前)流管道节点,调用操作包装Sink方法
        for (AbstractPipeline p=AbstractPipeline.this; p.depth > 0;p=p.previousStage) {
            sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
        }
        return (Sink<P_IN>) sink;
    }
	

wrapSink生成返回的结果如下图 (Sink.ChainedReference为两个匿名类)Sink指向第一个实例
在这里插入图片描述

    //第三个节点 StatelessOp 实例 调用AbstractPipeline实现的PipelineHelper方法
	//wrappedSink为Sink.ChainedReference的实例 spliterator为源拆分器(ArraySpliterator)
	@Override
    final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
        Objects.requireNonNull(wrappedSink);
		//非短路逻辑操作
        if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
            //表示传递给下游的操作数量 会依次调用下游操作的begin
            wrappedSink.begin(spliterator.getExactSizeIfKnown());
            //对拆分器中的任意元素执行此Consumer
            spliterator.forEachRemaining(wrappedSink);
            //调用end方法 会依次调用下游操作的end
            wrappedSink.end();
        }
        else {
            //短路逻辑操作
            copyIntoWithCancel(wrappedSink, spliterator);
        }
    }

	//ArraySpliterator的forEachRemaining方法 遍历操作
    @Override
    public void forEachRemaining(Consumer<? super T> action) {
            Object[] a; int i, hi; // hoist accesses and checks from loop
            if (action == null)
                throw new NullPointerException();
            if ((a = array).length >= (hi = fence) &&
                (i = index) >= 0 && i < (index = hi)) {
                do { action.accept((T)a[i]); } while (++i < hi);
            }
     }

	//先执行第一个Sink的操作 对每个元素执行完mapper操作后在调用下游的accept方法
	@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));
              }
         };
    }

	//执行下游的Sink的操作 对每一个元素过滤之后执行下游的accept方法
    @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);
                   }
           };
    }	
	//ForEachOp.OfRef的accept方法 consumer为终止操作传入的 此例子为输出方法
	@Override
    public void accept(T t) {
         consumer.accept(t);
    }

自此调用结束。

4.总结

Stream是使用spliterator实现的一种遍历操作、包含创建stream、中间操作和终止操作。只有在终止操作的时候spliterator才回去真正执行。

在构建过程中使用了双向链表将头和每一步操作包装成了(AbstractPipeline)、并将每一步操作的执行包装成了Sink

形成了一个操作链。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值