Stream的操作分为中间操作和终端操作。
中间操作: 由于stream的延迟性,中间操作相当于“我打算要进行这个操作,但是现在先不急着操作。”例如filter,sort,limit等。
终端操作:执行流的所有中间操作并且关闭流,使得流无法被复用。
中间操作
中间操作是对流中元素的一种操作,这个操作可以化为一个函数,实际上源码也是这样设计的。因此这里我直接举filter操作为例子。
首先我们看在interface Stream中对filter的定义.
Stream<T> filter(Predicate<? super T> predicate);
复制代码
返回由与此给定谓词匹配的此流的元素组成的流。
显然传入的是一个函数。
这时候往下看它的实现:
@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);
}
};
}
};
}
复制代码
我们可以看到,实现中使用了new,目前我认为在这个实现中并没有对源流的数据进行操作或者说它可能另外复制了一份流进行返回(虽然第二种可能性很低,因为效率的开销太大)。
然后再看opWrapSink方法,该方法使用了传入的函数
@Override
public void accept(P_OUT u) {
if (predicate.test(u))
downstream.accept(u);
}
复制代码
根据我做数据过滤的经历downstream.accept(u);操作应该是一个添加数据的操作。点进去查看之后发现他也是个函数
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
/** andThen */
}
复制代码
而ChainedReference这个类只是Sink接口中部分实现Sink的抽象类。而Sink继承了Consumer函数接口
而更上一层返回的StatelessOp类,他也是一个继承了ReferencePipeline并部分实现的抽象类。这里我们看到,StatelessOp是一个ReferencePipeline类,而ReferencePipeline类我在最早的StreamSupport的stream中已经知道了是一个原始流的类。也就是说它是一个新的流。那么它和旧的流之间是什么关系呢?
我们直接看最底层的构造方法的赋值
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;
}
复制代码
其中previousStage是旧的流,源码中称它为“上游管道”。然后我们可以看到
previousStage.nextStage = this;
复制代码
这行代码,到了这里既视感就很强烈了,这不就是链表吗?!那么根据源码我们可以知道stream中表示数据的Pipeline和中间操作新创建的Pipeline是链表关系,那么其他操作是不是一样呢?这里我快速查看了map操作:
@Override
@SuppressWarnings("unchecked")
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));
}
};
}
};
}
复制代码
返回的依旧是StatelessOp对象。