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. H3C 子网划分方法

  2. 关于redux和react-redux使用combinereducers之后的问题

    最近用react写项目的时候,开始复习之前学过的redux,记录一下一些坑,以防忘记 我现在的redux目录下有这么些东西 首先是index.js import { createStore } fro ...

  3. [Linux] 使用awk比较两个文件的内容

    当需要比较A , B两个文件 , A文件中存在 , 并且把也在B文件中存在的行去除掉 , 可以使用这个awk的用法来 awk  '{if(ARGIND==1) {val[$0]}else{if($0 ...

  4. MFC防止进程重复建立

    原文:https://blog.csdn.net/zhang11wu4/article/details/7100839 在APP类的InitInstance()的最前面加入以下代码,建立互斥区,可防止 ...

  5. Keras lstm 文本分类示例

    #基于IMDB数据集的简单文本分类任务 #一层embedding层+一层lstm层+一层全连接层 #基于Keras 2.1.1 Tensorflow 1.4.0 代码: '''Trains an LS ...

  6. RNN,LSTM

    RNN: Vanilla Neural Network :对单一固定的输入给出单一固定输出 Recurrent Neural Network:对单一固定的输入给出一系列输出(如:可边长序列),例:图片 ...

  7. 闯荡Linux帝国:nginx的创业故事

    前情回顾: NextStep帝国推出的web服务,迅速风靡比特宇宙,各星系帝国均蠢蠢欲动,想在这一波浪潮中掘一桶金. 详情参见:万维网的诞生 初出茅庐 小马哥和他的小伙伴小黑.大黄来到陌生的Linux ...

  8. StatePattern(状态模式)-----Java/.Net

    在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式. 在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context ...

  9. UML类图基础

    UML( Unified Modeling Language) 统一建模语言, 它是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持,包括由需求分析到规格,到构造和 ...

  10. LibreOJ6279. 数列分块入门 3 题解

    题目链接:https://loj.ac/problem/6279 题目描述 给出一个长为 \(n\) 的数列,以及 \(n\) 个操作,操作涉及区间加法,询问区间内小于某个值 \(x\) 的前驱(比其 ...