Java8 Stream流程解析

        前两天补了一下基础,重新学习了一下Java8新增的函数式接口以及ConsumerFunctionPredicateSupplier等几个接口,先简单介绍下这几个接口,对于理解后面的流程有一定帮助。

  • 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)以及一种非短路结束操作。

  1. 首先我们要知道调用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);
    }

  2. 其次我们要知道stream的所有中间操作不是立即执行的,而是返回了包含具体操作的lambda表达式的一个ReferencePipeline的子类,而这个类中会将当前需要执行的stream对象作为新对象的上一个(upstream)形成一个类似于链表的结构进行参数传递和函数调用,以便于后续的流式操作
  3. 综上所述,我们代码应该从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;
        }
  4. 解析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);
        }
  5.  继续解析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;
    	}
    }
  6. 看完了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()));
    }
  7. 由于此处入参的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();
    }
  8. 此处代码实现跟进到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));
    				}
    			};
    		}
    	};
    }
  9. 进入copyInto方法,参数是步骤5中的ReducingSink对象和步骤1中描述的集合元素的spliterator对象,然后执行到if里面,调用reducingSinkbegin方法,我们将步骤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;
    		}
    	};
    }
  10. 此处Spliterator接口中原本有forEachRemaining的实现,但是在我们使用的List的实现类ArrayList中,该方法实现了自己的spliterator方法,也就是说从步骤1中调用Collection接口的spliterator方法就不是执行的接口的默认方法,而是执行的ArrayList类中重写的spliterator方法,即接下来forEachRemaining方法应该执行ArrayListArrayListSpliterator类的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;
    	}
    }
  11. 该方法的参数是通过链式组合好的Stream的操作对象,主要通过action.accept(e)方法开始执行,代码将依次顺序执行操作链中的各种操作,例如此处先执行filter的方法过滤元素,其次取字符串的第一个元素,再进行去重,最终执行collect,而最终结束操作collect中ReducingSink的accept方法是执行accumulator.accept(state, t),而查看步骤3accumulator的实现是List::add方法引用,所以此处会将最终的元素添加到之前创建的空的集合中,并完成结束操作,在最后一个sink对象中存储一份经过stream处理好的集合对象,并最终执行end方法,此处在我们的操作流程中没有end方法的实现,所以结束该操作
  12. 代码依次执行到返回并跳转到上一个调用链,回到AbstractPipeline.java471行,copyInto方法结束,返回sink对象,此时的sink对象中存储了stream处理好的数据集合,随后该方法执行结束,回到ReduceOps.java708行中,wrapAndCopyInto方法返回的sink对象继续返回sink.get(),该方法会调用步骤5ReducingSink对象的父类的get方法,即Box类的get方法,而之前的操作都是将处理好的对象放在该类的成员变量state中,所以此处直接返回的state即是经过stream处理好的state
  13. 代码继续回到ReferencePipeline.java499行,此时的container的值即是之前返回的state,也就是stream处理好的对象了,最后在判断数据可以直接返回还是需要处理返回,并返回处理完成的新的ArrayList对象。

到此以该范例举例的Stream的操作流程解析就结束了,以上所有流程都是根据自己debug和分析得出的结论,可能有些地方不是很清晰或者不是很准确,也欢迎大家留言进行交流讨论,共同进步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值