在java8的流操作中分为终止符和非终止符。

非终止符不会触发数据的处理。

每次通过stream()方法新建立一个流的时候都会创建一个Head类。这个类是ReferencePipeline的一个内部类,同时也继承了ReferencePipeline,代表当前流的一个初始状态。之后每进行一次中间操作,都会根据操作的类型生成一个StatelessOp或者StatefulOp代表有无状态的中间操作,这些都和Head一样继承自ReferencePipeline。而ReferencePipeline继承自AbstractPipeline,可以看到AbstractPipeline中一个重要的成员。

private final AbstractPipeline previousStage;

结合下面的流操作的map()方法可以看到。

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) {@OverrideSink<P_OUT> opWrapSink(int flags, Sink<R> sink) {return new Sink.ChainedReference<P_OUT, R>(sink) {@Overridepublic void accept(P_OUT u) {downstream.accept(mapper.apply(u));}};}};
}

每次调用一次中间操作,的确没有真的进行关于数据的确切操作,而是重新返回了一个StatelessOp,对于这个map()方法,重写了opWrapSink()方法,这个方法将在终止符操作中被调用。在创建这个中间无状态操作符的时候,参数需要传入当前的流操作,最后在其父类的构造方法中将会被赋值给previousStage,也就是说,流操作中的中间操作,实则是以前一步操作为参数创建了一个新的操作符,只要根据previousStage往前回溯直到一开始创建stream得到的Head类就是整个流操作的逆序,也就是说,在流操作的过程中遇到终止符之前,一直都是往链表之前创建新的操作符节点。

然而,仅仅建立这样一个链表显然是不够的,每个中间操作符都重写了opWrapSink()方法,在终止符操作具体的数据之间,将会从链表的头部一次调用链表中的操作符节点的opWrapSink()方法,进行具体的流操作包装。

在调用到类似forEach()的终止操作时候,将会正式对流进行包装,可以看到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.previousStage) {sink = p.opWrapSink(p.previousStage.combinedFlags, sink);}return (Sink<P_IN>) sink;
}

在这个方法中,链表头部,也就是流操作的最后一个中间操作,将会不断调用其在一开始重写的opWrapSink()方法,对流进行包装。

以map()和limit()各自实现的opWrapSink()方法为例子。

@Override
Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {return new Sink.ChainedReference<P_OUT, R>(sink) {@Overridepublic void accept(P_OUT u) {downstream.accept(mapper.apply(u));}};
}@Override
Sink<T> opWrapSink(int flags, Sink<T> sink) {return new Sink.ChainedReference<T, T>(sink) {long n = skip;long m = limit >= 0 ? limit : Long.MAX_VALUE;@Overridepublic void begin(long size) {downstream.begin(calcSize(size, skip, m));}@Overridepublic void accept(T t) {if (n == 0) {if (m > 0) {m--;downstream.accept(t);}}else {n--;}}@Overridepublic boolean cancellationRequested() {return m == 0 || downstream.cancellationRequested();}};
}

可以看到,不管具体的操作如何,实则都是生成的都是一个ChainedReference类,这个类都将上一个包装完毕的类作为参数存放到自己的downstream属性中,这样,本身逆序的链表,将会从内到外进行包装,最后生成的包装类的最外层正式有逻辑正序上第一个操作符所产生的ChainedReference,而这个ChainedReference实现的accept()方法中,实现的正是具体的逻辑操作,并将本次操作的结果作为参数交给由它包装的downstream,也就是逻辑上下一个操作符所产生的ChainedReference调用accept()方法执行下一步逻辑操作,通过不断的包装达到流操作的目的。

java8的stream流操作的数据结构相关推荐

  1. Java8中Stream流对集合操作

    java8中Stream流引入函数式编程思想,主要配合各种接口.lambda表达式.方法引用等方式,为集合的遍历.过滤.映射等提供非常"优雅"的操作方式. Student.java ...

  2. Java8种Stream流相关操作——集合的筛选、归约、分组、聚合

    过滤.筛选   filter skip /*** 过滤 筛选*/@Testpublic void test2(){List<String> list = Arrays.asList(&qu ...

  3. 吃透JAVA的Stream流操作,多年实践总结

    在JAVA中,涉及到对数组.Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行处理. 例如,现在有这么一个需求: 从给定句子中返回单词 ...

  4. Java8的 Stream 流的各种用法

    Java8 的 Stream 流的各种用法 什么是Stream 1. Stream可以由数组或集合创建,对流的操作分为两种 2. Stream的特性 3. Stream可以通过集合数组创建 4. st ...

  5. Java8特性 stream流常用方法

    Java8特性 stream流常用方法 Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据. Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方 ...

  6. 【小家java】Stream流操作的有状态 vs 无状态

    相关阅读 [小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小 ...

  7. List的Stream流操作

    Stream流 Stream 中文称为 "流",通过将集合转换为这么一种叫做 "流" 的元素序列,通过声明性方式,能够对集合中的每个元素进行一系列并行或串行的流 ...

  8. List增删元素后size大小发生变化带来的影响、Stream流操作、Lambda表达式

    目录 List增删元素后size大小发生变化带来的影响 List的几种遍历方式 报异常原因 增强for循环原理 异常原理 建议删除操作 性能对比 Stream流操作 Lambda表达式 语法 Lamb ...

  9. 【java基础】吐血总结Stream流操作

    文章目录 Stream流操作讲解 在这里插入图片描述 1 Stream概述 2 Stream与传统遍历对比 3 Stream的创建 4 Stream的使用 4.1 遍历/匹配(foreach.find ...

最新文章

  1. linux系统调用挂钩方法总结
  2. 使用 COM 风格的编程接口
  3. 后台开发技术--接入层设计
  4. asp.net权限设置可能导致应用程序无法正常运行(转)
  5. 一图感受各种机器学习算法
  6. java Servlet Session
  7. OCR技术系列实践:银行卡、身份证、门牌号、护照、车牌、印刷体汉字识别
  8. 牛客第三场多校 H Diff-prime Pairs
  9. python爬取京东手机配置信息(正则)
  10. mysql表索引类型修改_MySQL常用的建表、添加字段、修改字段、添加索引SQL语句写法总结...
  11. 7. Nginx 预定义变量
  12. 只因少写一个判空,我的代码上线后炸了!
  13. android 人脸识别边框_Android实现简单的人脸识别
  14. 江民10日病毒播报称:小心“硬盘魔鬼”等病毒感染
  15. CLUSTERDOWN Hash slot not served 记录一次线上redis插槽问题
  16. Excel怎么随机生成偶数
  17. 毕业论文用尾注添加参考文献
  18. 【LeetCode Python实现】 5473. 灯泡开关 IV(中等)
  19. what is pathon?(脚本语言pathon简介)
  20. vue.js的项目实战 1

热门文章

  1. Android之通过HttpURLConnection.getResponseCode状态码抛出异常的问题以及解决方法
  2. vue动态禁用控件绑定disable
  3. js中判断对象数据类型的方法
  4. WebService之初体验
  5. PyQt5笔记(08) – 输入对话框
  6. cpu针脚测试软件,Sandsifter:一款专门针对X86处理器的模糊测试工具
  7. 包含几通道数据_温度采集,无处不测!「数据采集」
  8. Pyton学习—字符串
  9. iOS开发工程师笔试题
  10. 从关系型数据库到非关系型数据库