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。
  1. private static void testSerial() {
  2. Integer[] integers = new Integer[]{1,2,3,4,5,6,7,8,9,10};
  3. logger.info("1. create a integer stream, without terminal operation");
  4. Stream<Integer> integerStream = Arrays.asList(integers).stream()
  5. .map(integer->{
  6. logger.info("multiply {} with 10", integer);
  7. return integer * 10;
  8. })
  9. .map(integer -> {
  10. logger.info("add {} with 5", integer);
  11. return integer + 5;
  12. });
  13. logger.info("2. add a terminal operation to stream");
  14. List<Integer> integerList = integerStream.collect(Collectors.toList());
  15. logger.info("3. result {}", integerList);
  16. }

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

  1. [20:53:52:765] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.testSerial(PracticeMain.java:19) - 1. create a integer stream, without terminal operation
  2. [20:53:52:821] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.testSerial(PracticeMain.java:29) - 2. add a terminal operation to stream
  3. [20:53:52:827] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 1 with 10
  4. [20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 10 with 5
  5. [20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 2 with 10
  6. [20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 20 with 5
  7. [20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 3 with 10
  8. [20:53:52:829] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 30 with 5
  9. [20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 4 with 10
  10. [20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 40 with 5
  11. [20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 5 with 10
  12. [20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 50 with 5
  13. [20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 6 with 10
  14. [20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 60 with 5
  15. [20:53:52:830] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 7 with 10
  16. [20:53:52:831] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 70 with 5
  17. [20:53:52:832] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 8 with 10
  18. [20:53:52:832] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 80 with 5
  19. [20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 9 with 10
  20. [20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 90 with 5
  21. [20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$0(PracticeMain.java:22) - multiply 10 with 10
  22. [20:53:52:833] [INFO] - [main] - com.wangdan.practice.stream.PracticeMain.lambda$testSerial$1(PracticeMain.java:26) - add 100 with 5
  23. [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. 2019-8-30-C#-反射调用私有事件

    title author date CreateTime categories C# 反射调用私有事件 lindexi 2019-08-30 08:52:57 +0800 2018-09-19 20: ...

  2. JOISC2014 挂饰("01"背包)

    传送门: [1]:洛谷 [2]:BZOJ 参考资料: [1]:追忆:往昔 •题解 上述参考资料的讲解清晰易懂,下面谈谈我的理解: 关键语句: 将此题转化为 "01背包" 类问题,关 ...

  3. UWP IRandomAccessStream 与 Stream 互转

    本文告诉大家如何将 IRandomAccessStream 和 Stream 互转 如果在使用网络传输文件的时候,在 UWP 经常使用将 IRandomAccessStream 和 Stream 互转 ...

  4. QuartusII 13.0的完美破解

    网络上破解QuartusII 13.0软件的方法都不行,最后经过本人总结测试(独创),最终实现了QuartusII 13.0的破解,破解方法如下: 网上常规操作之后,会得到一个“license.dat ...

  5. VMware虚拟机安装Windows2003操作教程

    1.下载好以下三个文件: 2.选择VMware安装包,跟随指令安装好后,打开: 3.选择"创建新的虚拟机"后,选择"安装光盘映像文件(iso)",点击浏览载入. ...

  6. 深度解读 - TDD详细(测试驱动开发)

    本文结构: 什么是 TDD 为什么要 TDD 怎么 TDD FAQ 学习路径 延伸阅读 什么是 TDD TDD 有广义和狭义之分,常说的是狭义的 TDD,也就是 UTDD(Unit Test Driv ...

  7. 【t056】智力问答(链表+计数排序做法)

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 新年联欢会上,G.Sha负责组织智力问答节目.G.Sha建立了一个很大很大的超级题库,并衡量了每道题的 ...

  8. es6笔记 day2---函数默认参数、箭头函数、剩余参数

    函数变化: 1.函数默认参数 2.函数参数默认是已经定义了,不能再使用let.const声明 3.扩展运算符.rest运算符 ...就是扩展运算符,它的作用就是把数组给展开 结合函数使用传参,也可以将 ...

  9. ssh批量免密

    expect命令在linux下实现批量ssh免密 发布时间:2017-11-27 08:41:39 投稿:laozhang 本次文章主要给大家讲解了在linux系统下用expect命令实现批量ssh免 ...

  10. slim中的参数获取

    官方文档中对于get和post的参数有以下获取方式 $app->get('/', function (Request $req, Response $res, $args = []) { $my ...