筛选和切片
- filter 方法
- distinct 方法
- limit 方法
- skip 方法
谓词筛选
Stream 接口支持 filter 方法,该操作会接受一个谓词(一个返回 boolean的函数)作为参数,并返回一个包括所有符合谓词的元素的流。
|
|
筛选重复的元素
Stream 接口支持 distinct 的方法, 它会返回一个元素各异(根据流所生成元素的 hashCode和equals方法实现)的流。例如,以下代码会筛选出列表中所有的偶数,并确保没有 重复。
|
|
限制元素数量
Stream 支持limit(n)方法,该方法会返回一个不超过给定长度的流。所需的长度作为参数传递 给limit。如果流是有序的,则最多会返回前n个元素。
|
|
跳过指定数量的元素
Stream 支持 skip(n) 方法,返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一 个空流。limit(n) 和 skip(n) 是互补的。
|
|
映射
map 操作
Stream 支持 map 方法,它会接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映 射成一个新的元素
|
|
flatMap 操作
flatmap 方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。
|
|
给定两个数字列表,如何返回所有的数对呢?例如,给定列表[1, 2, 3]和列表[3, 4],应该返回[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]。
|
|
查找和匹配
anyMatch
流中是否有一个元素能匹配给定的谓词。
|
|
allMatch
流中是否有所有元素能匹配给定的谓词。
|
|
nonMatch
流中是否有没有任何元素能匹配给定的谓词。
|
|
findAny
findAny 方法将返回当前流中的任意一个元素。
|
|
findFirst
findAny 方法将返回当前流中的第一个元素。
|
|
Optional
Optional<T>
类(java.util.Optional)是一个容器类,代表一个值存在或不存在。Optional里面y有几种显式地检查值是否存在或处理值不存在的情形的方法:
isPresent()
将在Optional包含值的时候返回true, 否则返回false。ifPresent(Consumer<T> block)
)会在值存在的时候执行给定的代码块。T get()
会在值存在时返回值,否则抛出一个NoSuchElement异常。T orElse(T other)
会在值存在时返回值,否则返回一个默认值。
归约(reduce)
把一个流中的元素组合起来,使用 reduce 操作来表达更复杂的查 询,比如“计算菜单中的总卡路里”或“菜单中卡路里最高的菜是哪一个”。此类查询需要将流中所有元素反复结合起来,得到一个值,比如一个Integer。这样的查询可以被归类为归约操作 (将流归约成一个值)。
reduce操作是如何作用于一个流的:Lambda反复结合每个元素,直到流被归约成一个值。reduce方法接受两个参数:一个初始值,这里是0;一个 BinaryOperator<T>
来将两个元素结合起来产生一个新值, 这里我们用的是 lambda (a, b) -> a + b
。
元素求和
|
|
最大值
|
|
最小值
|
|
数值流
原始类型流特化
Java 8引入了三个原始类型特化流接口来解决这个问题: IntStream 、 DoubleStream 和 LongStream,分别将流中的元素特化为int、long和double,从而避免了暗含的装箱成本。每 个接口都带来了进行常用数值归约的新方法,比如对数值流求和的sum,找到最大元素的max。 此外还有在必要时再把它们转换回对象流的方法。这些特化的原因并不在于流的复杂性,而是装箱造成的复杂性——即类似int和Integer之间的效率差异。
- 映射到数值流:将流转换为特化版本的常用方法是mapToInt、mapToDouble和mapToLong。这些方法和前 面说的map方法的工作方式一样,只是它们返回的是一个特化流,而不是
Stream<T>
。
|
|
- 转换回对象流
通过 box 方法可以将数值流转化为 Stream 非特化流。
|
|
- 默认值 OptionalInt
Optional 可以用 Integer、String等参考类型来参数化。对于三种原始流特化,也分别有一个Optional原始类 型特化版本:OptionalInt、OptionalDouble和OptionalLong。
|
|
数值范围
|
|
Java 8引入了两个可以用于IntStream和LongStream的静态方法,帮助生成这种范围: range和rangeClosed。这两个方法都是第一个参数接受起始值,第二个参数接受结束值。但 range是不包含结束值的,而rangeClosed则包含结束值。
数值流应用:勾股数
生成 (5, 12, 13)、(6, 8, 10)和(7, 24, 25) 这样有效的勾股数数组集合。
|
|
构建流
值创建流
|
|
数组创建流
|
|
文件生成流
|
|
函数生成流:创建无限流
|
|
示例实战
假设你是执行交易的交易员。你的经理让你为八个查询找到答案。你能做到吗?
- (1) 找出2016年发生的所有交易,并按交易额排序(从低到高)。
- (2) 交易员都在哪些不同的城市工作过?
- (3) 查找所有来自于北京的交易员,并按姓名排序。
- (4) 返回所有交易员的姓名字符串,按字母顺序排序。
- (5) 有没有交易员是在深圳工作的?
- (6) 打印生活在北京的交易员的所有交易额。
- (7) 所有交易中,最高的交易额是多少?
- (8) 找到交易额最小的交易。
交易员类
|
|
交易类
|
|
计算
|
|
小结
- 中间操作表
操作 | 类型 | 返回类型 | 目的 |
---|---|---|---|
filter | 中间操作 | Stream<T> |
过滤元素 |
distinct | 中间操作 | Stream<T> |
过滤重复的元素 |
skip | 中间操作 | Stream<T> |
跳过指定数量的元素 |
limit | 中间操作 | Stream<T> |
限制元素的数量 |
map | 中间操作 | Stream<T> |
流的转化 |
flatmap | 中间操作 | Stream<T> |
流的扁平化 |
sorted | 中间操作 | Stream<T> |
元素排序 |
- 终端操作表
操作 | 类型 | 返回类型 | 目的 |
---|---|---|---|
forEach | 终端操作 | void | 消费流中的每个元素,返回void |
count | 终端操作 | long | 返回流中元素的个数,返回long |
collect | 终端操作 | R | 把流归约为一个集合 |
anyMatch | 终端操作 | boolean | 流中是否有符合要求的元素 |
noneMatch | 终端操作 | boolean | 流中是否没有任何符合要求的元素 |
allMatch | 终端操作 | boolean | 流中是否所有元素都是符合要求的 |
findAny | 终端操作 | Optional |
查找符合要求的元素 |
findFirst | 终端操作 | Optional |
查找第一个符合要求的元素 |
reduce | 终端操作 | Optional |
归约 |
参考资料
《Java 8 实战》