Java Stream 流(Stream API)详细讲解
一、什么是 Stream 流
1.1 Stream 的本质
Stream 是 Java 8 引入的一套用于 集合数据处理的函数式 API。
需要明确几点:
- Stream 不是数据结构
- Stream 不存储数据
- Stream 不修改原集合
- Stream 关注的是 对数据的"计算过程"
可以把 Stream 理解为:
对集合中的数据,建立一条"流水线",数据依次经过各种操作,最终得到结果。
1.2 为什么要使用 Stream
在没有 Stream 之前,我们通常这样写代码:
java
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = new ArrayList<>();
for (int x : list) {
if (x % 2 == 0) {
result.add(x * x);
}
}
问题:
- 代码冗长
- 不利于并行计算
使用 Stream:
java
List<Integer> result = list.stream()
.filter(x -> x % 2 == 0)
.map(x -> x * x)
.toList();
二、Stream 的核心特点
2.1 三大特性
- 不存储数据
- 惰性执行
- 一次性消费
2.2 惰性执行示例
java
list.stream()
.filter(x -> {
System.out.println("filter: " + x);
return x > 2;
});
上面代码 不会输出任何内容,因为:
没有终止操作,Stream 不会真正执行
三、Stream 的整体使用流程
Stream 使用分为 三步:
数据源 → 中间操作 → 终止操作
示意:
java
list.stream() // 获取流
.filter(...) // 中间操作
.map(...) // 中间操作
.forEach(...); // 终止操作
四、创建 Stream 的方式
4.1 从集合创建
java
List<Integer> list = List.of(1, 2, 3);
Stream<Integer> stream = list.stream();
4.2 从数组创建
java
int[] arr = {1, 2, 3};
IntStream stream = Arrays.stream(arr);
4.3 使用 Stream.of
java
Stream<String> stream = Stream.of("A", "B", "C");
4.4 创建无限流
java
Stream<Integer> stream = Stream.iterate(0, x -> x + 2);
stream.limit(5).forEach(System.out::println);
五、中间操作(Intermediate Operations)
中间操作特点:
- 返回新的 Stream
- 支持链式调用
- 不会立刻执行
5.1 filter(过滤)
java
list.stream()
.filter(x -> x > 3)
.forEach(System.out::println);
5.2 map(映射)
java
list.stream()
.map(x -> x * 2)
.forEach(System.out::println);
5.3 flatMap(扁平化)
java
List<List<Integer>> lists = List.of(
List.of(1, 2),
List.of(3, 4)
);
lists.stream()
.flatMap(List::stream)
.forEach(System.out::println);
5.4 distinct(去重)
java
list.stream()
.distinct()
.forEach(System.out::println);
5.5 sorted(排序)
java
list.stream()
.sorted()
.forEach(System.out::println);
六、终止操作(Terminal Operations)
终止操作特点:
- 触发 Stream 执行
- 返回结果或副作用
- 一个 Stream 只能有一个终止操作
6.1 forEach
java
list.stream().forEach(System.out::println);
6.2 collect
java
List<Integer> newList = list.stream()
.filter(x -> x > 2)
.collect(Collectors.toList());
6.3 reduce(归约)
java
int sum = list.stream()
.reduce(0, Integer::sum);
6.4 count / anyMatch / allMatch
java
long count = list.stream().count();
boolean hasEven = list.stream().anyMatch(x -> x % 2 == 0);
七、并行流(Parallel Stream)
7.1 使用方式
java
list.parallelStream()
.map(x -> x * x)
.forEach(System.out::println);
或:
java
list.stream()
.parallel()
.forEach(System.out::println);
7.2 注意事项
- 并行流 不保证顺序
- 不适合 I/O 密集型任务
- 共享变量可能产生线程安全问题
八、Stream 常见误区
8.1 Stream 会修改原集合?
不会。
8.2 Stream 可以重复使用?
不可以。
java
Stream<Integer> s = list.stream();
s.forEach(System.out::println);
s.forEach(System.out::println); // 抛异常
九、Stream 与传统 for 循环对比
| 对比项 | for 循环 | Stream |
|---|---|---|
| 编程风格 | 命令式 | 声明式 |
| 可读性 | 一般 | 高 |
| 并行能力 | 手动 | 内置 |
| 易错性 | 高 | 低 |
十、总结
- Stream 是 数据处理工具,不是容器
- 核心思想是 流水线 + 函数式编程
- 牢记三步:创建 → 中间操作 → 终止操作
- 合理使用,不要滥用并行流