Java 8 stream特性是一个能快速降低开发人员工作量的语法糖,用起来很简单,用好了很难。这里就通过一系列的博客对几个常见的错误进行解释说明,并给出替代方法。这里先说明串行和终止操作。

首先,给出IBM官网给出的介绍,请仔细阅读。

https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

流的操作类型分为两种:

  • Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
  • Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。

在对于一个 Stream 进行多次转换操作 (Intermediate 操作),每次都对 Stream 的每个元素进行转换,而且是执行多次,这样时间复杂度就是 N(转换次数)个 for 循环里把所有操作都做掉的总和吗?其实不是这样的,转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在 Terminal 操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。

这里给出一个例子:

  1. 创建一个整型stream,对1到10的流进行处理,分别将流中的数值乘以10、加上5,得到一个Stream对象integerStream。
  2. 对integerStream进行collect,得到一个List对象integerList。
  3. 输出integerList。
private static void testSerial() {
Integer[] integers = new Integer[]{1,2,3,4,5,6,7,8,9,10};
logger.info("1. create a integer stream, without terminal operation");
Stream<Integer> integerStream = Arrays.asList(integers).stream()
.map(integer->{
logger.info("multiply {} with 10", integer);
return integer * 10;
})
.map(integer -> {
logger.info("add {} with 5", integer);
return integer + 5;
});
logger.info("2. add a terminal operation to stream");
List<Integer> integerList = integerStream.collect(Collectors.toList());
logger.info("3. result {}", integerList);
}

根据下面的日志,可以确定,在第一步创建Stream对象时, intermediate 操作并没有被立即执行,在第二步执行 terminal 操作,Stream中的所有步骤才被执行。而且第一步中创建的两个intermediate 操作,会依次处理同一个数据,也就是说对于所有数据,先被第一个map操作处理,处理结果再被第二个map操作处理,然后被收集到List中。

[20:53:52:765] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.testSerial(PracticeMain.java:19) - 1. create a integer stream, without terminal operation
[20:53:52:821] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.testSerial(PracticeMain.java:29) - 2. add a terminal operation to stream
[20:53:52:827] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 1 with 10
[20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 10 with 5
[20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 2 with 10
[20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 20 with 5
[20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 3 with 10
[20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 30 with 5
[20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 4 with 10
[20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 40 with 5
[20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 5 with 10
[20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 50 with 5
[20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 6 with 10
[20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 60 with 5
[20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 7 with 10
[20:53:52:831] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 70 with 5
[20:53:52:832] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 8 with 10
[20:53:52:832] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 80 with 5
[20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 9 with 10
[20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 90 with 5
[20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 10 with 10
[20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 100 with 5
[20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.testSerial(PracticeMain.java:31) - 3. result [15, 25, 35, 45, 55, 65, 75, 85, 95, 105]

理解Stream(一)——串行与终止操作的更多相关文章

  1. iOS:GCD理解1(串行-并行、同步-异步)

    1.获取并行.创建串行 队列 1-1).获取 并行(全局) 队列 ,DISPATCH_QUEUE_PRIORITY_DEFAULT 为默认优先级. dispatch_queue_t global_qu ...

  2. 关于ORACLE的串行化隔离级别--来自ORACLE概念手册

    为了描述同时执行的多个事务如何实现数据一致性,数据库研究人员定义了被 称为串行化处理(serializability)的事务隔离模型(transaction  isolation model).当所有 ...

  3. for循环与串行化、并行化Stream流性能对比

    第四章 并行化Stream流 关注公众号(CoderBuff)回复"stream"获取<Java8 Stream编码实战>PDF完整版. <Java8 Strea ...

  4. Linux 串行终端,虚拟终端,伪终端,控制终端,控制台终端的理解

    转自Linux 串行终端,虚拟终端,伪终端,控制终端,控制台终端的理解 终端:输入和输出设备(键盘 + 显示器). 串行终端:与机器的串口对应,每一个串口对应一个串行终端,串口对应的是物理终端. 虚拟 ...

  5. FS BPM 业余研发(用户详细操作手册--单人串行/并行)之 深圳分公司技术部请假审批流程

    1.FS BPM 简介 BPM软件中BPM是英文字母缩写,大致有二个意思.第一.Business Process Management,即业务流程管理,是一套达成企业各种业 务环节整合的全面管理模式. ...

  6. OC 线程操作 - GCD使用 -同步函数,异步函数,串行队列,并发队列

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ // GCD 开几条线程并不是我们 ...

  7. 【Java8新特性】面试官:谈谈Java8中的Stream API有哪些终止操作?

    写在前面 如果你出去面试,面试官问了你关于Java8 Stream API的一些问题,比如:Java8中创建Stream流有哪几种方式?(可以参见:<[Java8新特性]面试官问我:Java8中 ...

  8. iOS:GCD理解1(同步-异步、串行-并行)

    1.并行-异步(ST1与ST2抢占资源) 1-1).获取 并行(全局)队列 ,DISPATCH_QUEUE_PRIORITY_DEFAULT 为默认优先级. dispatch_queue_t queu ...

  9. ios多线程操作(五)—— GCD串行队列与并发队列

          GCD的队列能够分为2大类型,分别为串行队列和并发队列      串行队列(Serial Dispatch Queue):      一次仅仅调度一个任务,队列中的任务一个接着一个地运行( ...

随机推荐

  1. Vmware虚拟机用户密码忘记了怎么办?

    Vmware虚拟机用户密码忘记了怎么办?   虚拟机Linux上用户密码忘记了怎么办? 今天准备再学习一下linux操作系统,由于之前已经安装过vaware和linux(redhat),所以这次认为不 ...

  2. easyui—window在vue-element-ui中的使用(坑)

    自己给自己挖的坑 !!! 项目中,布局外层使用easyui框架中的window;内部显示内容的table使用element-ui框架,需求将window使用border-image作为边框,之后发现拉 ...

  3. LINUX内核参数调优集锦

    1.linux内核参数注释 2.两种修改内核参数方法 3.内核优化参数生产配置 1.linux内核参数注释 以下表格中红色字体为常用优化参数 根据参数文件所处目录不同而进行分表整理 下列文件所在目录: ...

  4. Java基础系列8——IO流超详细总结

    该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 在初学Java时,I ...

  5. Vue仿网易云PC端的网页

    贴个网址:https://github.com/wangjie3186594/-PC- 声明一下:这个网页没做完!没做完!没做完!      本人新人一枚,按照的是我当前的学习进度做的项目,很多效果未 ...

  6. 错误 1 未能找到类型或命名空间名称“”, 引入DLL文件出现提示文件不存在问题

    在所有引入都正确的情况下,查看项目目标框架是否正确

  7. Android应用框架中的四个核心要点

    Android应用框架中的四个核心要点:活动(Activity).消息(Intent).视图(View).任务(Task) (一)活动Activity Android系统内部有专门的Activity堆 ...

  8. callback、promise和async、await的使用方法

    callback 回调是一个函数被作为一个参数传递到另一个函数里,在那个函数执行完后再执行.通俗的讲就是 B函数被作为参数传递到A函数里,在A函数执行完后再执行B. promise Promise 是 ...

  9. MySQL基础之事务编程学习笔记

    MySQL基础之事务编程学习笔记 在学习<MySQL技术内幕:SQL编程>一书,并做了笔记.本博客内容是自己学了<MySQL技术内幕:SQL编程>事务编程一章之后,根据自己的理 ...

  10. 优雅的使用 ThreadLocal

    前言 在我们日常 Java Web 开发中难免遇到需要把一个参数层层的传递到最内层,然后中间层根本不需要使用这个参数,或者是仅仅在特定的工具类中使用,这样我们完全没有必要在每一个方法里面都传递这样一个 ...