Stream 终止操作
字数: 0 字 时长: 0 分钟
1. 概述
终结操作用于结束 Stream 的处理流程,并得到最终结果。
常见终结操作:
forEach
count
max / min
anyMatch / allMatch / noneMatch
findAny / findFirst
reduce
collectStream 的基本执行过程:
数据源
↓
创建 Stream
↓
中间操作
↓
终结操作
↓
得到最终结果终结操作会触发前面的中间操作真正执行。
一个 Stream 执行终结操作之后,就不能再次使用。
2. forEach()
forEach() 用于遍历 Stream 中的元素,并对每个元素执行指定操作。
例如:输出所有作者的姓名,并去重。
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getName())
.distinct()
.forEach(name -> System.out.println(name));可以理解为:
Stream 中的元素
↓
逐个取出
↓
执行指定操作3. count()
count() 用于统计当前 Stream 中元素的数量。
返回值类型:
long例如:统计作者一共出版了多少本不同的书。
List<Author> authors = getAuthors();
long count = authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.count();
System.out.println(count);4. max() 和 min()
max() 和 min() 分别用于获取 Stream 中的最大值和最小值。
由于 Stream 可能为空,所以返回值使用:
Optional<T>4.1 max()
获取所有书籍中的最高评分:
List<Author> authors = getAuthors();
Optional<Integer> max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max((o1, o2) -> o1 - o2);
max.ifPresent(score -> System.out.println(score));4.2 min()
获取所有书籍中的最低评分:
List<Author> authors = getAuthors();
Optional<Integer> min = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.min((o1, o2) -> o1 - o2);
min.ifPresent(score -> System.out.println(score));5. 查找和匹配
Stream 提供了一组用于判断和查找元素的终结操作:
anyMatch()
allMatch()
noneMatch()
findAny()
findFirst()5.1 anyMatch()
anyMatch() 用于判断:
是否至少有一个元素满足条件。
只要有一个元素满足条件,就返回 true。
例如:判断是否存在年龄大于 29 岁的作者。
匿名内部类写法:
List<Author> authors = getAuthors();
boolean result = authors.stream()
.anyMatch(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge() > 29;
}
});
System.out.println(result);Lambda 写法:
List<Author> authors = getAuthors();
boolean result = authors.stream()
.anyMatch(author -> author.getAge() > 29);
System.out.println(result);5.2 allMatch()
allMatch() 用于判断:
是否所有元素都满足条件。
所有元素都满足条件时返回 true,否则返回 false。
例如:判断所有作者是否都已经成年。
List<Author> authors = getAuthors();
boolean result = authors.stream()
.allMatch(author -> author.getAge() > 18);
System.out.println(result);5.3 noneMatch()
noneMatch() 用于判断:
是否没有任何元素满足条件。
如果所有元素都不满足指定条件,则返回 true。
例如:判断是否没有作者超过 100 岁。
List<Author> authors = getAuthors();
boolean result = authors.stream()
.noneMatch(author -> author.getAge() > 100);
System.out.println(result);三个匹配方法可以简单记成:
anyMatch()
↓
至少一个满足
allMatch()
↓
全部满足
noneMatch()
↓
一个都不满足5.4 findAny()
findAny() 用于获取 Stream 中的任意一个元素。
返回值:
Optional<T>它不能保证获取到的一定是第一个元素。
例如:获取任意一个年龄大于 18 岁的作者。
List<Author> authors = getAuthors();
Optional<Author> any = authors.stream()
.filter(author -> author.getAge() > 18)
.findAny();
any.ifPresent(author -> System.out.println(author.getName()));5.5 findFirst()
findFirst() 用于获取 Stream 中的第一个元素。
返回值:
Optional<T>例如:获取年龄最小的作者,并打印姓名。
List<Author> authors = getAuthors();
Optional<Author> first = authors.stream()
.sorted((o1, o2) -> o1.getAge().compareTo(o2.getAge()))
.findFirst();
first.ifPresent(author -> System.out.println(author.getName()));这里先按照年龄升序排序:
年龄最小
↓
年龄较大然后通过 findFirst() 获取第一个元素。
6. reduce()
reduce() 用于按照指定的计算规则,将 Stream 中的多个元素最终合并成一个结果。
可以理解为:
多个元素
↓
不断进行计算
↓
一个结果例如:
1、2、3、4、5
↓
求和
↓
156.1 两个参数的 reduce()
常见形式:
reduce(identity, accumulator)其中:
identity:初始值accumulator:计算规则
内部执行逻辑可以简单理解为:
T result = identity;
for (T element : stream) {
result = accumulator.apply(result, element);
}
return result;传统循环求和:
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int result = 0;
for (int i : arr) {
result = result + i;
}
System.out.println(result);这里的:
0就类似 reduce() 中的 identity。
6.2 求所有作者年龄之和
匿名内部类写法:
List<Author> authors = getAuthors();
Integer result = authors.stream()
.map(author -> author.getAge())
.reduce(0, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer element) {
return result + element;
}
});
System.out.println(result);Lambda 写法:
List<Author> authors = getAuthors();
Integer result = authors.stream()
.map(author -> author.getAge())
.reduce(0, (result, element) -> result + element);
System.out.println(result);执行过程可以理解为:
identity = 0
0 + 第一个年龄
↓
结果 + 第二个年龄
↓
结果 + 第三个年龄
↓
最终结果6.3 求最大年龄
使用 Integer.MIN_VALUE 作为初始值:
List<Author> authors = getAuthors();
Integer result = authors.stream()
.map(author -> author.getAge())
.reduce(
Integer.MIN_VALUE,
(result, element) ->
result < element ? element : result
);
System.out.println(result);每次比较:
result
↘
比较 → 保留较大的值
↗
element最终得到最大年龄。
6.4 求最小年龄
使用 Integer.MAX_VALUE 作为初始值:
List<Author> authors = getAuthors();
Integer result = authors.stream()
.map(author -> author.getAge())
.reduce(
Integer.MAX_VALUE,
(result, element) ->
result > element ? element : result
);
System.out.println(result);每次比较后保留较小的值,最终得到最小年龄。
6.5 一个参数的 reduce()
另一种形式:
reduce(accumulator)它没有指定初始值,因此会使用 Stream 中的元素参与第一次计算。
由于 Stream 可能为空,所以返回值为:
Optional<T>内部逻辑可以简单理解为:
boolean foundAny = false;
T result = null;
for (T element : stream) {
if (!foundAny) {
foundAny = true;
result = element;
} else {
result = accumulator.apply(result, element);
}
}
return foundAny
? Optional.of(result)
: Optional.empty();例如求作者最小年龄。
匿名内部类写法:
List<Author> authors = getAuthors();
Optional<Integer> result = authors.stream()
.map(author -> author.getAge())
.reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer element) {
return result < element ? result : element;
}
});
result.ifPresent(age -> System.out.println(age));Lambda 写法:
List<Author> authors = getAuthors();
Optional<Integer> result = authors.stream()
.map(author -> author.getAge())
.reduce(
(result, element) ->
result < element ? result : element
);
result.ifPresent(age -> System.out.println(age));没有指定初始值的
reduce()返回Optional,因为 Stream 可能没有任何元素。
7. collect()
collect() 也是 Stream 中非常重要的终结操作,用于将 Stream 中的数据收集成其他数据结构。
常见的收集方式:
Collectors.toList()
Collectors.toSet()
Collectors.toMap()例如:
List<String> names = authors.stream()
.map(author -> author.getName())
.collect(Collectors.toList());collect() 和 Collectors 的内容较多,单独整理在:
Collectors.md8. 常用终结操作小结
| 方法 | 作用 |
|---|---|
forEach() | 遍历元素 |
count() | 统计元素数量 |
max() | 获取最大值 |
min() | 获取最小值 |
anyMatch() | 判断是否至少一个元素满足条件 |
allMatch() | 判断是否所有元素都满足条件 |
noneMatch() | 判断是否所有元素都不满足条件 |
findAny() | 获取任意一个元素 |
findFirst() | 获取第一个元素 |
reduce() | 将多个元素归并成一个结果 |
collect() | 收集 Stream 中的数据 |
可以简单记成:
forEach
↓
遍历
count
↓
统计
max / min
↓
最值
xxxMatch
↓
判断
findXxx
↓
查找
reduce
↓
归并
collect
↓
收集终结操作执行后,当前 Stream 就已经被消费,不能再次使用。