理解Stream(一)——串行与终止操作
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 对应的集合,然后对每个元素执行所有的函数。
这里给出一个例子:
- 创建一个整型stream,对1到10的流进行处理,分别将流中的数值乘以10、加上5,得到一个Stream对象integerStream。
- 对integerStream进行collect,得到一个List对象integerList。
- 输出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(一)——串行与终止操作的更多相关文章
- iOS:GCD理解1(串行-并行、同步-异步)
1.获取并行.创建串行 队列 1-1).获取 并行(全局) 队列 ,DISPATCH_QUEUE_PRIORITY_DEFAULT 为默认优先级. dispatch_queue_t global_qu ...
- 关于ORACLE的串行化隔离级别--来自ORACLE概念手册
为了描述同时执行的多个事务如何实现数据一致性,数据库研究人员定义了被 称为串行化处理(serializability)的事务隔离模型(transaction isolation model).当所有 ...
- for循环与串行化、并行化Stream流性能对比
第四章 并行化Stream流 关注公众号(CoderBuff)回复"stream"获取<Java8 Stream编码实战>PDF完整版. <Java8 Strea ...
- Linux 串行终端,虚拟终端,伪终端,控制终端,控制台终端的理解
转自Linux 串行终端,虚拟终端,伪终端,控制终端,控制台终端的理解 终端:输入和输出设备(键盘 + 显示器). 串行终端:与机器的串口对应,每一个串口对应一个串行终端,串口对应的是物理终端. 虚拟 ...
- FS BPM 业余研发(用户详细操作手册--单人串行/并行)之 深圳分公司技术部请假审批流程
1.FS BPM 简介 BPM软件中BPM是英文字母缩写,大致有二个意思.第一.Business Process Management,即业务流程管理,是一套达成企业各种业 务环节整合的全面管理模式. ...
- OC 线程操作 - GCD使用 -同步函数,异步函数,串行队列,并发队列
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ // GCD 开几条线程并不是我们 ...
- 【Java8新特性】面试官:谈谈Java8中的Stream API有哪些终止操作?
写在前面 如果你出去面试,面试官问了你关于Java8 Stream API的一些问题,比如:Java8中创建Stream流有哪几种方式?(可以参见:<[Java8新特性]面试官问我:Java8中 ...
- iOS:GCD理解1(同步-异步、串行-并行)
1.并行-异步(ST1与ST2抢占资源) 1-1).获取 并行(全局)队列 ,DISPATCH_QUEUE_PRIORITY_DEFAULT 为默认优先级. dispatch_queue_t queu ...
- ios多线程操作(五)—— GCD串行队列与并发队列
GCD的队列能够分为2大类型,分别为串行队列和并发队列 串行队列(Serial Dispatch Queue): 一次仅仅调度一个任务,队列中的任务一个接着一个地运行( ...
随机推荐
- linux平台依赖性
每个电脑平台有其自己的特点, 内核设计者可以自由使用所有的特性来获得更好的性能. in the target object file ??? 不象应用程序开发者, 他们必须和预编译的库一起连接他们的代 ...
- dotnet 使用 GC.GetAllocatedBytesForCurrentThread 获取当前线程分配过的内存大小
在 dotnet framework 4.8 的时候支持调用 GC.GetAllocatedBytesForCurrentThread 获取当前线程分配过的内存大小 创建一个简单的控制台程序,在调用 ...
- vue-learning:12-vue获取模板内容的方式
vue获取模板内容的方式 目录 outerHTML获取内容 template属性获取内容 ES6的字符串模板 <template>标签 <srcipt type="text ...
- jdk+tomcat+mysql一键安装脚本
最近在搞一个web项目部署,每次都要安装jdk.配置环境变量.安装tomcat和mysql.对于非开发人员,还是有点难度的,经常出错,然后就整理了一个自动化的脚本. JDKinstall.bat @e ...
- sklearn各种分类器简单使用
sklearn中有很多经典分类器,使用非常简单:1.导入数据 2.导入模型 3.fit--->predict 下面的示例为在iris数据集上用各种分类器进行分类: #用各种方式在iris数据集上 ...
- 超简单!pytorch入门教程(二):Autograd
一.autograd自动微分 autograd是专门为了BP算法设计的,所以这autograd只对输出值为标量的有用,因为损失函数的输出是一个标量.如果y是一个向量,那么backward()函数就会失 ...
- OSI协议介绍
应用层 为网络用户或应用程序提供各种服务,代表协议有Telnet,FTP,HTTP,SNMP等 表示层 负责所传输的信的语法和语义,用于处理再多个通信系统之间交换信息的表示方式,代表协议有ASCII, ...
- c# T4模板生成实体类(sqlserver)
1.用vs新建tt文件. 2.tt文件保存就自动运行 3.tt文件代码如下,设置生成cs文件的命名空间和生成地址 <#@ template language="C#" hos ...
- 并查集的超市问题---溜TM的
三个月前我就错了,现在又错了,我就是个傻****** 服了,看图哇 打扰了... #include<cstdio> #include<iostream> #include< ...
- 如何学习Java基础
Java是用于软件开发的最流行的编程语言,无论做自动化测试或者测试开发,Java依然是最重要的选项之一. 为什么要学习Java? Java很容易学习 Java是通用的,面向对象的,高性能,解释型,安全 ...