Stream源码分析

传递行为和传递对象

在Spliterator中,终于遇到了一个在固有的java面向对象编程的思想中很难理解的一件事情,那就是传递对象和传递行为。代码如下

@Override
        default boolean tryAdvance(Consumer<? super Integer> action) {
            if (action instanceof IntConsumer) {
                return tryAdvance((IntConsumer) action);
            }
            else {
                if (Tripwire.ENABLED)
                    Tripwire.trip(getClass(),
                                  "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
                return tryAdvance((IntConsumer) action::accept);
            }
        }

这是一段在Spliterator中具象化为特例Int类型的Spliterator,这一段代码中,我们可以看到,这里面的IntConsumer和Consumer两个类型,他们并没有关联关系,即非继承,
在这里插入图片描述
在这里插入图片描述
那么,他们为什么能实现强制类型转换呢?正常来讲这里的编译会出现错误,但是这就是在Java8中新增加的函数式编程所带来的效果,即–》传递行为,也就是说
在这里插入图片描述

Stream()

调用了Collection.stream()方法,
在这里插入图片描述
这里的ReferencePipeline.head实现了ReferencePipeline而他们就是Stream。
ReferencePipeline表示流的源stage和中间stage,
而ReferencePipeline.Head实现了对源数据的源stage的操作。
head是没有previousStage的,而ReferencePipeline有。
他们都有一个泛型<E_IN,E_OUT>,代表上游管道进入element和产出element。

For sequential streams, and parallel streams without stateful intermediate
operation, parallel streams, pipeline evaluation is done in a single pass that
“jams” all the operations together.

这是指流管道会将所有操作一起执行。

Collection.stream()其实就是构造一个spliterator来构造一个源及头。

而这里这个spliterator是被各种集合子类Overwrite了,所以,当调用foreach方法时,

foreach方法在源直接调用时调用的是head中的foreach,否则调用的是ReferencePipeline中的foreach。

调用的其实是foreachRemaining,而这个是各个子类实现中的foreachRemaining。

我们来看一下构建的头操作和中间操作。
在这里插入图片描述
这是头节点。调用了super(source,sourceFlags,parallel)也就是AbstractPipeline
在这里插入图片描述
中间节点都一样,我们以map为例。
在这里插入图片描述
我们可以看到map构造了一个StatelessOp对象,这个对象也是ReferencePipeline的一个子类实现。同样的也调用了super(source,sourceFlag)也就是AbstractPipeline。
然后我们来看这个AbstractPipeline。
上面的构造头,下面的构造中间类型,但是他们返回的都是AbstractPipeline。
在这里插入图片描述
他们的不同点一目了然,比如深度,比如是否有perviousstage等等。

而从上上图中,我们可以看到每一个中间操作其实都是创建了一个StatelessOp这样一个对象。这个对象里面重写了opWrapSink方法,然后创建了新的ChainedReference对象。
这个链式引用对象就关联了上下游的关系。
在这里插入图片描述
对于filter,是通过谓词来判断是否需要继续执行,如下
在这里插入图片描述
而对于map我们则可以理解为一种装饰者模式。对于每一个元素来说,都是先进行调用上游的Function再去执行下游的accept,是以元素作为执行链的基本单元。而不是执行完了整个管道的Function再去执行整个管道的Filter
在这里插入图片描述
而Sink中相比他的父类Consumer增加了模版模式的方法begin和end,形成了一个类似双向链表的调用链。
ChainedReference就对Sink进行了实现。来实现了上文我所说到的调用链关联上下游的一种功能。

猜你喜欢

转载自blog.csdn.net/weixin_39781526/article/details/85207550
今日推荐