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
形成了一个操作链。