Java8作为一个跨度极大,新功能巨多的版本,推出了许多实用的新API,其中一个比较重要的新的抽象称为流Stream,一种可以让你以声明的方式来处理集合等数据的强大新特性。
Stream 使用lambda语法来提供一种对 Java 集合运算和表达的高阶抽象。通过这种方式,可以很方便直观的指定希望对集合的具体操作,与此同时,底层的相关执行操作则会交给具体实现来决定。
在深入探究新特性之前,需要简单了解什么是流(Stream),以及什么是管道(pipeline)。
什么是 Stream?
流(Stream)是来自于现实中水流的概念延伸,在这里,流是一个来自数据源的元素队列,并支持聚合操作。
需要确认一点的是,我们这里所描述的Stream同常规输入输出流中的Stream不同,Java8新特性中的Stream提供了对集合的增强操作,并极大的提高了操作集合对象的便利性。
不同于集合本身,流并不会存储值数据,而是会根据实际的需求,来处理计算集合中的值,并将最终的操作结果返回。集合作为流的源,创建流不会导致其本身的数据流动。
流背后的思想是延迟计算:只到需要时才会计算值。
下面为通用格式下,所描述的流操作流转数据形式。
+--------------------+ +------+ +------+ +---+ +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+ +------+ +------+ +---+ +-------+
什么是Pinpline?
管道(pipeline)概念可以简单理解为现实中存储水流的水管,其用于存储具体某条流动中待处理的流数据,并负责将其运输到下一个待操作的管道。
Stream的常规实现,是通过若干个组合起来的管道实现的。管道会接受来自于流中的数据源,然后通过中间操作进行各种转换,并将流数据传输到下一个管道。该操作会一直持续到终止操作停止。
Stream操作的三个步骤
Stream的常规生命周期操作有三个操作步骤:创建 Stream、中间操作、结束操作。
创建 Stream
一般情况下流是针对集合进行操作,集合接口有两个方法来生成流:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
中间操作
中间操作只是一种标记,相当于操作链,只有结束操作才会触发实际计算。比如fifter、distinct、limit、skip、map、sorted等。
中间操作又可以分为无状态的(Stateless)和有状态的(Stateful)。
- 无状态中间操作是指元素的处理不受前面元素的影响。
- 有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果。
结束操作
结束操作又可以分为短路操作和非短路操作。
- 短路操作是指不用处理全部元素就可以返回结果,比如“找到第一个满足条件的元素”。
- 非短路操作则是指将所有的元素遍厉完成,直到最后才结束,通常用来收集自己想要的完整数据。
以下为常见的流在管道中,整个生命周期的各项操作。
操作 | 属性/状态 | 具体方法 |
---|---|---|
创建 Stream | 串行流 | stream() |
并行流 | parallelStream() | |
中间操作(Intermediate operations) | 无状态(Stateless) | unordered() filter() map() mapToInt() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() peek() |
有状态(Stateful) | distinct() sorted() limit() skip() | |
结束操作(Terminal operations) | 非短路操作 | orEach() forEachOrdered() toArray() reduce() collect() max() min() count() |
短路操作(short-circuiting) | anyMatch() allMatch() noneMatch() findFirst() findAny() |
接下来的几章,将按照Stream操作的三个步骤,深入研究分析java8的新特性Stream具体如何操作,以及在实际应用中的使用。