Java8 Stream的底层是怎么实现的

600 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

Stream的底层是怎么实现的

下面我们通过简单的示例来简单看看是怎么实现的:

/**
 * 筛选并统计信息
 *
 * @param list
 * @return
 */
private static long filterAndCount(List<Integer> list) {
    return list.stream().filter(i -> i % 2 == 0).count();
}

流的创建

stream.drawio.png

时序图比较简单,最后一步RefrencePipeline构造比较关键。Head是RefrencePipeline的子类,可以理解为Head是流水线的第一个stage。

  AbstractPipeline(Spliterator<?> source,
                   int sourceFlags, boolean parallel) {
      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;
      this.depth = 0;
      this.parallel = parallel;
  }

这里主要是存储了sourceSpliterator(这里为ArrayList$ArrayListSpliterator)。

中间操作

public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
    // 判断给定的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) {
                    //重置Sink状态(不确定数据大小)
                    downstream.begin(-1);
                }

                @Override
                public void accept(P_OUT u) {
                    //如果匹配就接收这个元素
                    if (predicate.test(u))
                        downstream.accept(u);
                }
            };
        }
    };
}

这里创建了一个StatelessOp(无状态操作,元素的处理不受之前元素的影响)继承了ReferencePipeline,构造的时候把this传进去了,实现了opWrapSink方法(接收了一个Sink又返回了一个Sink)。

具体调用等末端操作再看。

Sink

Consumer的一个扩展,用于在流管道的各个阶段执行值,并使用其他方法来管理大小信息、流控制等。在首次对Slink调用accept()方法之前,必须调用begin()方法来通知它数据即将到来(可选地通知接收器有多少数据即将到来),并且在发送所有数据之后,必须调用end()方法。在调用end()之后,不应该在neuter再次调用begin()的情况下调用accept()。Sink还提供了一种机制,通过该机制,接收器可以协同发送信号,表示它不希望接收更多的数据(cancellationRequested()方法),源可以在接收器发送更多数据之前轮询该方法。

RefrencePieline最终会将整个Stream流操作组装成一个调用链,而这条调用链上的各个Stream操作的上下关系就是通过Sink接口协议来定义实现的。

末端操作

count.drawio.png

末端操作能看出Stream底层是怎么实现的、惰性执行是怎么实现的

  • ReferencePieline#mapToLong
@Override
public final LongStream mapToLong(ToLongFunction<? super P_OUT> mapper) {
    Objects.requireNonNull(mapper);
    return new LongPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
                                  StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
        @Override
        Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
            return new Sink.ChainedReference<P_OUT, Long>(sink) {
                @Override
                public void accept(P_OUT u) {
                    downstream.accept(mapper.applyAsLong(u));
                }
            };
        }
    };
}

在count之前会把元素映射成1L,也是使用Sink来实现。

  • ReduceOps#makeLong
public static TerminalOp<Long, Long>
makeLong(long identity, LongBinaryOperator operator) {
    Objects.requireNonNull(operator);
    class ReducingSink
            implements AccumulatingSink<Long, Long, ReducingSink>, Sink.OfLong {
        private long state;

        @Override
        public void begin(long size) {
            //初始值赋值
            state = identity;
        }

        @Override
        public void accept(long t) {
            //进行累加
            state = operator.applyAsLong(state, t);
        }

        @Override
        public Long get() {
            return state;
        }

        @Override
        public void combine(ReducingSink other) {
            accept(other.state);
        }
    }
    return new ReduceOp<Long, Long, ReducingSink>(StreamShape.LONG_VALUE) {
        @Override
        public ReducingSink makeSink() {
            return new ReducingSink();
        }
    };
}
  • AbstractPieline#wrapSink
 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.pre
         sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
     }
     return (Sink<P_IN>) sink;
 }

Pipeline也是链式结构,遍历包装成sink并返回,返回的是Sink.ChainedReference(本身也是个sink)实例,是一个链式结构,从外到内(从第一个中间操作到最后一个末端操作)。

  • AbstractPieline#copyInto
final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
    Objects.requireNonNull(wrappedSink);

    if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
        // 重置sink状态以接收新的数据集
        wrappedSink.begin(spliterator.getExactSizeIfKnown());
        // 进行遍历,这里依次调用filter->count
        spliterator.forEachRemaining(wrappedSink);
        wrappedSink.end();
    }
    else {
        copyIntoWithCancel(wrappedSink, spliterator);
    }
}