美文网首页
java1.8 stream源码解析(串行stream)

java1.8 stream源码解析(串行stream)

作者: 老鼠抗大枪 | 来源:发表于2018-08-24 14:05 被阅读0次

    常用的流操作

    在深入原理之前,我们有必要知道关于Stream的一些基础知识,关于Stream的操作分类,如表1-1所示。

    表1-1 Stream的常用操作分类(表格引自这里)

    如表1-1中所示,Stream中的操作可以分为两大类:中间操作与结束操作,中间操作只是对操作进行了记录,只有结束操作才会触发实际的计算(即惰性求值),这也是Stream在迭代大集合时高效的原因之一。中间操作又可以分为无状态(Stateless)操作与有状态(Stateful)操作,前者是指元素的处理不受之前元素的影响;后者是指该操作只有拿到所有元素之后才能继续下去。结束操作又可以分为短路与非短路操作,这个应该很好理解,前者是指遇到某些符合条件的元素就可以得到最终结果;而后者是指必须处理所有元素才能得到最终结果。

    源码解读

    最基础类对应有ReferencePipeline以及终结操作对应的ops(例如forEach对应的是ForEachOps),请求有大体分为两种SHORT_CIRCUIT和非SHORT_CIRCUIT,非SHORT_CIRCUIT表示请求会依次得到sink处理,SHORT_CIRCUIT表示请求可能会中断,只处理其中某些因子。对于链式处理会将所有的链依次生成对应的sink链,后续会介绍

    打个比方stream1.filter(predicate1).filter(predicate2).forEach(consumer1);

    首先会调用ReferencePipeline的filter,生成StatelessOp的op,主要可以关注opWrapSink方法,然再次调用filter生成职责链,通过previousStage进行串接,类似于生成了opForPredicate2 ->opForPredicate1,然后调用终结函数forEach,通过ForEachOps生成ForEachOp的终结sink,然后调用FroEachOp的evaluateSequential进行请求处理,然后就是访问者模式相互访问来去,看源码的时候关心点放在如下图:

    wrapSink就是为了将最后的consumer通过前面介绍的sinkChain进行包装,生成opForPredicate1Sink->opForPredicate2Sink->consumerAction.

    然后通过是否为short_circuit进行不同处理,非short_circuit表示所有的属性都要进行操作,否则表示要进行筛选终结。

    非short_circuit如下:

    比如数组的,获取每个数组元素,进行action.accept,其中accept就是上面讲解的sinkChain.

    short_circuit如下:

    以limit为例子,先电泳forEachWithCancel,首先判断sink是或否需要取消请求,sliceOp对应的opWrapSink会维护一个m,每次处理一个请求就会减一。当为0 的时候就结束循环。

    最后,对于stream1.filter(predicate1).limit(1).filter(predicate2).forEach(consumer1);

    解析为:生成predicate1Sink->sliceOpSink(m=1)->predicate2Sink->consumer1Action,

    依次遍历stream1中的元素(stream1对应的spliterator的tryAdvance方法),然后判断sinkChain是否需要cancelRequest(predicate1->sliceOpSink->predicate2Sink),如果需要处理,则调用spliterator的tryAdvance执行sinkChain

    相关文章

      网友评论

          本文标题:java1.8 stream源码解析(串行stream)

          本文链接:https://www.haomeiwen.com/subject/jebbiftx.html