流介绍
目录
流是什么
流是对Java API的更新,允许你以声明式的方式操作数据集合。首先看一个例子,假设你想获得所有热量低于400卡的菜肴的名字,并按热量排序。在Java 8之前,你可以这样做:
|
|
在Java 8之后,你只需这样做:
|
|
要利用多核体系结构并行执行此代码,只需将stream()
更改为parallelStream()
|
|
总之,Java 8中的流API允许你编写这样的代码
- 声明式:更简洁,可读性更强
- 可组合:更灵活
- 可并行:更好的性能
开始使用流
首先,流到底是什么?一个简短的定义是,来自某个数据源的支持数据处理操作的元素序列。
- 元素序列:与集合类似,流提供了访问特定类型元素集的接口。集合是关于数据的,流是关于计算的。
- 数据源:流从数据源(如集合、数组或I/O资源)消费。从集合生成的流保留了集合中元素的顺序。
- 数据处理操作:流支持类似数据库的操作,以及函数式编程语言的常见操作来操作数据。比如filter,map,reduce,find, match, sort等。流操作可以顺序执行,也可以并行执行。
此外,流操作还有两个重要特征:
- 流管道:许多流操作返回流本身,允许将操作链接起来形成一个更大的流管道。这样可以支持某些优化,比如惰性求值和短路求值。在数据源上的流管道操作可以看作类似数据库的查询。
- 内部迭代:与集合相反,流操作在内部进行迭代。
流与集合
只遍历一次
与迭代器类似,流只能遍历一次,遍历之后流就被消耗殆尽了。你可以从初始数据源获得一个新的流来再次遍历它。
|
|
外部迭代与内部迭代
集合需要用户进行迭代,比如使用foreach,这称为外部迭代。与之相反,流使用内部迭代,即为你执行迭代,并负责将流产生的值存储在某个地方,你只需提供一个函数说明要做什么。
流操作
可以连接的流操作称为中间操作,关闭流的操作称为结束操作。
中间操作
中间操作(如filter或sorted)返回另一个流,这允许将操作连接起来形成查询。重要的是,在调用结束操作之前,中间操作不会执行任何处理,它们是惰性求值的。这是因为中间操作通常可以被结束操作合并一次处理。
结束操作
结束操作从流管道产生一个非流值结果。
使用流
总而言之,使用流通常包括三个部分:
- 执行查询的数据源,比如集合
- 形成流管道的一系列中间操作
- 执行流管道并产生结果的结束操作
下表总结了一些常见流操作。
操作 | 类型 | 返回类型 | 参数 | 函数描述符 |
---|---|---|---|---|
filter | 中间操作 | Stream<T> | Predicate<T> | T -> boolean |
map | 中间操作 | Stream<R> | Function<T, R> | T -> R |
limit | 中间操作 | Stream<T> | ||
sorted | 中间操作 | Stream<T> | Comparator<T> | (T, T) -> int |
distinct | 中间操作 | Stream<T> | ||
forEach | 结束操作 | void | Consumer<T> | T -> void |
count | 结束操作 | long | ||
collect | 结束操作 | R | Collector<T, A, R> |