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. Jmeter完整Demo

    1:创建一个线程组 2:添加一个cookie管理器 3:设置你的信息头管理器:application/json;text/plain;charset=UTF-8 44 4:添加一个用户参数,做全局变量 ...

  2. 台州学院第十二届校赛记录(B,C,E,H,I,J,L)

    传送门:点我 题目很棒,感谢出题验题的大佬们. 细节坑不少,是好事. 还是很菜,继续加油! B: 桃子的生日 时间限制(普通/Java):1000MS/3000MS     内存限制:65536KBy ...

  3. dotnet core 集成到 Mattermost 聊天工具

    在找了很久的团队交流工具,发现了 Mattermost 最好用,但是还需要做一些定制化的功能,于是就找到了 Mattermost 插件开发,还找到了如何自己写服务集成到 Mattermost 里面 本 ...

  4. 浮点数NaN和INF(#IND, #INF)

    NaN&INF定义在一些情况会出现无效的浮点数,例如除0,例如负数求平方根等,像这类情况,获取到的浮点数的值是无效的. NaN 即 Not a Number         非数字 INF  ...

  5. 微信群打卡机器人XiaoV项目开源 | 蔡培培的独立博客

    原文首发于蔡培培的独立博客.原文链接<微信群打卡机器人XiaoV项目开源>. 5月21日,在米花(后面" 亚里士多德式友谊"专题会提及)的影响下,决定搞个私人运动群,拉 ...

  6. 曹工说Spring Boot源码(6)-- Spring怎么从xml文件里解析bean的

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  7. DataTable转成实体列表 和 DataRow转成实体类

    #region DataTale转为实体列表 /// <summary> /// DataTale转为实体列表 /// </summary> /// <typeparam ...

  8. springboot多租户设计

    1. 概述 根据不同用户的请求,选择不同的数据源,不同的数据源可以是Oracle.MySQL或者其它.用到的技术栈,没有什么复杂的技术,可以看到,依赖也就加了几个而已,如下: 2. 先睹为快 如下图, ...

  9. Appium+Pytest实现app并发测试

    前言 这个功能已经写完很长时间了,一直没有发出来,今天先把代码发出来吧,有一些代码是参考网上写的,具体的代码说明今天暂时先不发了,代码解释的太详细还得我花点时间^_^, 毕竟想让每个人都能看明白也不容 ...

  10. spring cloud Gateway简单使用

    一.引子 2年前有幸使用过一次Spring Cloud (1.5.9),那次用的是ZUUL做网关,没有使用Gateway做网关,一直是个小遗憾.终于在2年后的19年底再次使用Spring Cloud, ...