还看不懂同事的代码?超强的 Stream 流操作姿势还不学习一下
Java 8 新特性系列文章索引。
前言
我们都知道 Lambda 和 Stream 是 Java 8 的两大亮点功能,在前面的文章里已经介绍过 Lambda 相关知识,这次介绍下 Java 8 的 Stream 流操作。它完全不同于 java.io 包的 Input/Output Stream ,也不是大数据实时处理的 Stream 流。这个 Stream 流操作是 Java 8 对集合操作功能的增强,专注于对集合的各种高效、便利、优雅的聚合操作。借助于 Lambda 表达式,显著的提高编程效率和可读性。且 Stream 提供了并行计算模式,可以简洁的编写出并行代码,能充分发挥如今计算机的多核处理优势。
在使用 Stream 流操作之前你应该先了解 Lambda 相关知识,如果还不了解,可以参考之前文章:还看不懂同事的代码?Lambda 表达式、函数接口了解一下 。
1. Stream 流介绍
Stream 不同于其他集合框架,它也不是某种数据结构,也不会保存数据,但是它负责相关计算,使用起来更像一个高级的迭代器。在之前的迭代器中,我们只能先遍历然后在执行业务操作,而现在只需要指定执行什么操作, Stream 就会隐式的遍历然后做出想要的操作。另外 Stream 和迭代器一样的只能单向处理,如同奔腾长江之水一去而不复返。
由于 Stream 流提供了惰性计算和并行处理的能力,在使用并行计算方式时数据会被自动分解成多段然后并行处理,最后将结果汇总。所以 Stream 操作可以让程序运行变得更加高效。
2. Stream 流概念
Stream 流的使用总是按照一定的步骤进行,可以抽象出下面的使用流程。
数据源(source) -> 数据处理/转换(intermedia) -> 结果处理(terminal )
2.1. 数据源
数据源(source)
也就是数据的来源,可以通过多种方式获得 Stream 数据源,下面列举几种常见的获取方式。
- Collection.stream(); 从集合获取流。
- Collection.parallelStream(); 从集合获取并行流。
- Arrays.stream(T array) or Stream.of(); 从数组获取流。
- BufferedReader.lines(); 从输入流中获取流。
- IntStream.of() ; 从静态方法中获取流。
- Stream.generate(); 自己生成流
2.2. 数据处理
数据处理/转换(intermedia)
步骤可以有多个操作,这步也被称为intermedia
(中间操作)。在这个步骤中不管怎样操作,它返回的都是一个新的流对象,原始数据不会发生任何改变,而且这个步骤是惰性计算
处理的,也就是说只调用方法并不会开始处理,只有在真正的开始收集结果时,中间操作才会生效,而且如果遍历没有完成,想要的结果已经获取到了(比如获取第一个值),会停止遍历,然后返回结果。惰性计算
可以显著提高运行效率。
数据处理演示。
@Test public void streamDemo(){ List<String> nameList = Arrays.asList("Darcy", "Chris", "Linda", "Sid", "Kim", "Jack", "Poul", "Peter"); // 1. 筛选出名字长度为4的 // 2. 名字前面拼接 This is // 3. 遍历输出 nameList.stream() .filter(name -> name.length() == 4) .map(name -> "This is "+name) .forEach(name -> System.out.println(name)); } // 输出结果 // This is Jack // This is Poul
数据处理/转换
操作自然不止是上面演示的过滤 filter
和 map
映射两种,另外还有 map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered 等。
2.3. 收集结果
结果处理(terminal )
是流处理的最后一步,执行完这一步之后流会被彻底用尽,流也不能继续操作了。也只有到了这个操作的时候,流的数据处理/转换
等中间过程才会开始计