前两天补了一下基础,重新学习了一下Java8新增的函数式接口以及Consumer,Function,Predicate,Supplier等几个接口,先简单介绍下这几个接口,对于理解后面的流程有一定帮助。
- Supplier 接口:
生产型接口,提供无参的get()方法由指定的lambda表达式实现返回指定泛型T的数据
- Consumer接口:
消费型接口,消费的数据类型由泛型T指定,提供accept(T t)方法和andThen(Consumer<? super T> after)方法,accept方法可以根据给定的lambda表达式消费数据,andThen方法可以在accept方法执行结束后执行后续的consumer实现的accept方法
看到这里我们就可以联想到Stream的链式操作了
- Predicate接口:
比较型接口,test(T t)方法用于对给定参数做逻辑判断,返回Boolean类型的结果
看到这里应该已经联想到stream对象的filter函数了,说不定多半是用这个接口来实现的呢
- Function接口:
给定一个T类型的参数返回一个R类型的结果,主要有两个方法apply(T t)和andThen(Function<? super R,? extends V> after) ,andThen方法也是可以在apply执行结束后执行after中的apply方法
回到正题,我们以一段代码来引入流程解析
List<String> nameList = Lists.newArrayList("大姐夫", "苏子卿", "川川", "子怡");
nameList.stream()
.filter(s -> s.length() > 2)
.map(s -> s.charAt(0))
.distinct()
.collect(Collectors.toList());
以上代码是将字符串集合进行了过滤,取第一个字符,去重,最终再转成List集合的过程,包含了两种中间操作(有状态Stateful,和无状态Stateless)以及一种非短路结束操作。
- 首先我们要知道调用collection.stream()方法后执行了什么操作,此处重点关注spliterator方法,其实现中返回了一个IteratorSpliterator对象,该对象内传入了调用的Collection对象this作为参数,后续在步骤9中会使用到。然后stream方法返回了一个ReferencePipeline对象,以提供stream的链式操作
// Collection.java 580行 default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); } // Collection.java 560行 @Override default Spliterator<E> spliterator() { return Spliterators.spliterator(this, 0); } // Spliterators.java 418行 public static <T> Spliterator<T> spliterator(Collection<? extends T> c, int characteristics) { return new IteratorSpliterator<>(Objects.requireNonNull(c), characteristics); } // StreamSupport.java 67行 public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) { Objects.requireNonNull(spliterator); return new ReferencePipeline.Head<>(spliterator, StreamOpFlag.fromCharacteristics(spliterator), parallel); }
- 其次我们要知道stream的所有中间操作不是立即执行的,而是返回了包含具体操作的lambda表达式的一个ReferencePipeline的子类,而这个类中会将当前需要执行的stream对象作为新对象的上一个(upstream)形成一个类似于链表的结构进行参数传递和函数调用,以便于后续的流式操作
- 综上所述,我们代码应该从collect方法内开始查看,首先Collectors.toList方法返回了一个CollectorImpl对象,将该对象的构造方法解析一下,得到如下描述:
// Collectors.java CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A,R> finisher, Set<Characteristics> characteristics) { // ArrayList::new this.supplier = supplier; // List::add this.accumulator = accumulator; // (left, right) -> { left.addAll(right); return left; } this.combiner = combiner; // i -> (R) i this.finisher = finisher; // CH_ID this.characteristics = characteristics; } CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Set<Characteristics> characteristics) { this(supplier, accumulator, combiner, castingIdentity(), characteristics); } public static <T> Collector<T, ?, List<T>> toList() { return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add, (left, right) -> { left.addAll(right); return left; }, CH_ID); } private static <I, R> Function<I, R> castingIdentity() { return i -> (R) i; }
- 解析collect方法内部细节,首先由于我们没有开启parallel并行执行,所以代码进入else中的evaluate(ReduceOps.makeRef(collector))
// ReferencePipeline 489行 @Override @SuppressWarnings("unchecked") public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) { A container; if (isParallel() && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT)) && (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) { container = collector.supplier().get(); BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator(); forEach(u -> accumulator.accept(container, u)); } else { container = evaluate(ReduceOps.makeRef(collector)); } return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH) ? (R) container : collector.finisher().apply(container); }
- 继续解析ReduceOps.makeRef(collector)方法,该方法返回了一个匿名内部类的ReduceOp对象,同时在重写方法里引用到了一个内部类,该方法会在后续进行调用,我们继续往下看
// ReduceOps.java 156行 public static <T, I> TerminalOp<T, I> makeRef(Collector<? super T, I, ?> collector) { Supplier<I> supplier = Objects.requireNonNull(collector).supplier(); BiConsumer<I, ? super T> accumulator = collector.accumulator(); BinaryOperator<I> combiner = collector.combiner(); class ReducingSink extends Box<I> implements AccumulatingSink<T, I, ReducingSink> { @Override public void begin(long size) { state = supplier.get(); } @Override public void accept(T t) { accumulator.accept(state, t); } @Override public void combine(ReducingSink other) { state = combiner.apply(state, other.state); } } return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) { @Override public ReducingSink makeSink() { return new ReducingSink(); } @Override public int getOpFlags() { return collector.characteristics().contains(Collector.Characteristics.UNORDERED) ? StreamOpFlag.NOT_ORDERED : 0; } }; } // ReduceOps 664行 private static abstract class Box<U> { U state; Box() {} // Avoid creation of special accessor public U get() { return state; } }
- 看完了makeRef方法我们继续来看evaluate方法,sourceSpliterator方法实现细节主要是拿到Stream的集合元素,也就是步骤1中所描述的那个spliterator,它里面存放着调用stream方法的集合元素,细节我们暂时不展开讲,继续往下走
// AbstractPipeline.java 226行 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())); }
- 由于此处入参的terminalOp对象为ReduceOps类中的ReduceOp类的匿名内部类实现,同时我们没有开启parallel并行,所以代码将执行evaluateSequential方法,实现细节应在ReduceOp类中:makeSink方法参考4中的代码实现,将返回一个内部类ReducingSink的对象,然后我们继续看wrapAndCopyInto方法
// ReduceOps.java 705行 @Override public <P_IN> R evaluateSequential(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) { return helper.wrapAndCopyInto(makeSink(), spliterator).get(); }
- 此处代码实现跟进到AbstractPipeline类中,先通过wrapSink方法,依次将stream中的中间操作的外层封装解开,获得内层的Sink接口的实现类对象,并将每个参数依次链式连接方便后续调用
// AbstractPipeline.java 469行 @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; } // AbstractPipeline.java 511行调用wrapSink的实现 @Override @SuppressWarnings("unchecked") 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; } // ReferencePipeline.java 160行调用Stream.filter的实现 @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); } }; } }; } // ReferencePipeline.java 182行调用Stream.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)); } }; } }; }
- 进入copyInto方法,参数是步骤5中的ReducingSink对象和步骤1中描述的集合元素的spliterator对象,然后执行到if里面,调用reducingSink的begin方法,我们将步骤5的代码再次贴到此处方便查看,此处的supplier是collector调用获取的,而collector是通过Collectors.toList()方法得到的,我们回到步骤3,可以看到该方法是一个lambda表达式的方法引用,调用该方法会执行ArrayList::new,也就是创建一个新的ArrayList集合,此处应该是作为存储结果元素的集合,此处继续往下看,执行forEachRemaining方法
// AbstractPipeline.java 476行 @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); wrappedSink.end(); } else { copyIntoWithCancel(wrappedSink, spliterator); } } // ReduceOps.java 155行 public static <T, I> TerminalOp<T, I> makeRef(Collector<? super T, I, ?> collector) { Supplier<I> supplier = Objects.requireNonNull(collector).supplier(); BiConsumer<I, ? super T> accumulator = collector.accumulator(); BinaryOperator<I> combiner = collector.combiner(); class ReducingSink extends Box<I> implements AccumulatingSink<T, I, ReducingSink> { @Override public void begin(long size) { state = supplier.get(); } @Override public void accept(T t) { accumulator.accept(state, t); } @Override public void combine(ReducingSink other) { state = combiner.apply(state, other.state); } } return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) { @Override public ReducingSink makeSink() { return new ReducingSink(); } @Override public int getOpFlags() { return collector.characteristics().contains(Collector.Characteristics.UNORDERED) ? StreamOpFlag.NOT_ORDERED : 0; } }; }
- 此处Spliterator接口中原本有forEachRemaining的实现,但是在我们使用的List的实现类ArrayList中,该方法实现了自己的spliterator方法,也就是说从步骤1中调用Collection接口的spliterator方法就不是执行的接口的默认方法,而是执行的ArrayList类中重写的spliterator方法,即接下来forEachRemaining方法应该执行ArrayList中ArrayListSpliterator类的forEachRemaining方法
// ArrayList.java 1269行 @Override public Spliterator<E> spliterator() { return new ArrayListSpliterator<>(this, 0, -1, 0); } // ArrayList.java 1275行 static final class ArrayListSpliterator<E> implements Spliterator<E> { private final ArrayList<E> list; private int index; // current index, modified on advance/split private int fence; // -1 until used; then one past last index private int expectedModCount; // initialized when fence set ArrayListSpliterator(ArrayList<E> list, int origin, int fence, int expectedModCount) { this.list = list; // OK if null unless traversed this.index = origin; this.fence = fence; this.expectedModCount = expectedModCount; } private int getFence() { // initialize fence to size on first use int hi; // (a specialized variant appears in method forEach) ArrayList<E> lst; if ((hi = fence) < 0) { if ((lst = list) == null) hi = fence = 0; else { expectedModCount = lst.modCount; hi = fence = lst.size; } } return hi; } public ArrayListSpliterator<E> trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : // divide range in half unless too small new ArrayListSpliterator<E>(list, lo, index = mid, expectedModCount); } public boolean tryAdvance(Consumer<? super E> action) { if (action == null) throw new NullPointerException(); int hi = getFence(), i = index; if (i < hi) { index = i + 1; @SuppressWarnings("unchecked") E e = (E)list.elementData[i]; action.accept(e); if (list.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } return false; } 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]; action.accept(e); } if (lst.modCount == mc) return; } } throw new ConcurrentModificationException(); } public long estimateSize() { return (long) (getFence() - index); } public int characteristics() { return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; } }
- 该方法的参数是通过链式组合好的Stream的操作对象,主要通过action.accept(e)方法开始执行,代码将依次顺序执行操作链中的各种操作,例如此处先执行filter的方法过滤元素,其次取字符串的第一个元素,再进行去重,最终执行collect,而最终结束操作collect中ReducingSink的accept方法是执行accumulator.accept(state, t),而查看步骤3中accumulator的实现是List::add方法引用,所以此处会将最终的元素添加到之前创建的空的集合中,并完成结束操作,在最后一个sink对象中存储一份经过stream处理好的集合对象,并最终执行end方法,此处在我们的操作流程中没有end方法的实现,所以结束该操作
- 代码依次执行到返回并跳转到上一个调用链,回到AbstractPipeline.java471行,copyInto方法结束,返回sink对象,此时的sink对象中存储了stream处理好的数据集合,随后该方法执行结束,回到ReduceOps.java708行中,wrapAndCopyInto方法返回的sink对象继续返回sink.get(),该方法会调用步骤5中ReducingSink对象的父类的get方法,即Box类的get方法,而之前的操作都是将处理好的对象放在该类的成员变量state中,所以此处直接返回的state即是经过stream处理好的state
- 代码继续回到ReferencePipeline.java499行,此时的container的值即是之前返回的state,也就是stream处理好的对象了,最后在判断数据可以直接返回还是需要处理返回,并返回处理完成的新的ArrayList对象。
到此以该范例举例的Stream的操作流程解析就结束了,以上所有流程都是根据自己debug和分析得出的结论,可能有些地方不是很清晰或者不是很准确,也欢迎大家留言进行交流讨论,共同进步