在 Java 中,Stream(流) 是 Java 8 引入的核心特性,本质是 对数据源(集合、数组等)进行高效操作的 "元素序列" ------ 它不存储数据,也不修改原数据源,而是通过一系列 "中间操作"(如过滤、排序、映射)和 "终端操作"(如收集、遍历、统计),以声明式(而非命令式)的方式处理数据,让代码更简洁、高效、易读。
一、先搞懂:Stream 不是什么?
- 不是集合 / 数组:不存储元素,仅 "流经" 元素(类似水流,只传递数据,不保存);
- 不修改原数据源:所有操作都返回新的 Stream 或最终结果,原始数据不变;
- 不是迭代器:但支持类似迭代的 "遍历",且支持并行处理(无需手动写多线程);
- 一次性使用:Stream 被终端操作消费后,就不能再重复使用(需重新创建)。
二、Stream 的核心特性
1. 声明式编程(关注 "做什么",而非 "怎么做")
命令式编程(Java 8 前):需手动写循环、判断逻辑(如筛选偶数);声明式编程(Stream):直接描述 "筛选偶数" 的目标,底层实现由 Stream 框架完成。
示例对比:
// 命令式(手动循环筛选)
List<Integer> numbers = Arrays.asList(1,2,3,4,5);
List<Integer> evens = new ArrayList<>();
for (int num : numbers) {
if (num % 2 == 0) {
evens.add(num);
}
}
// 声明式(Stream 筛选)
List<Integer> evens = numbers.stream()
.filter(num -> num % 2 == 0)
.collect(Collectors.toList());
2. 中间操作 + 终端操作(惰性执行)
- 中间操作 :返回新的 Stream,不立即执行(如
filter、sorted、map、limit);多个中间操作可 "链式调用",形成操作管道(Pipeline); - 终端操作 :触发实际计算,消费 Stream,返回非 Stream 结果(如
forEach、collect、count、average);只有调用终端操作,中间操作才会一起执行(惰性执行,提升效率)。
示例:
numbers.stream()
.filter(num -> num % 2 == 0) // 中间操作(不执行)
.sorted() // 中间操作(不执行)
.forEach(System.out::println); // 终端操作(触发所有中间操作执行)
3. 支持并行处理(简单高效)
Stream 分为 "串行流" 和 "并行流":
- 串行流:单线程处理(默认,
stream()生成); - 并行流:多线程处理(
parallelStream()生成或parallel()转换),无需手动管理线程。
示例(并行筛选偶数,自动多线程):
List<Integer> evens = numbers.parallelStream()
.filter(num -> num % 2 == 0)
.collect(Collectors.toList());
4. 无状态 + 有状态操作
- 无状态:每个元素的处理不依赖其他元素(如
filter、map),效率高; - 有状态:处理元素需依赖其他元素(如
sorted需收集所有元素才能排序,limit需计数),可能需要缓存。
三、Stream 的核心结构(3 步流程)
使用 Stream 通常分为 3 步:创建 Stream → 中间操作(链式)→ 终端操作(触发执行)
1. 第一步:创建 Stream(4 种常见方式)
- 从集合创建(最常用):
list.stream()(串行)、list.parallelStream()(并行); - 从数组创建:
Arrays.stream(数组)或Stream.of(数组元素); - 从值创建:
Stream.of(1,2,3,4); - 生成无限流:
Stream.generate(()->Math.random())(需用limit终止)。
示例:
// 1. 集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();
// 2. 数组创建
String[] arr = {"x", "y", "z"};
Stream<String> stream2 = Arrays.stream(arr);
// 3. 直接创建
Stream<Integer> stream3 = Stream.of(10, 20, 30);
// 4. 无限流(生成 5 个随机数)
Stream<Double> randomStream = Stream.generate(Math::random).limit(5);
2. 第二步:中间操作(常用 API)
之前学过的 filter、sorted、limit 都是中间操作,再补充几个核心:
map(Function):将元素映射为另一种类型(如整数转字符串、对象取属性);distinct():去重(基于equals()方法);skip(long n):跳过前 n 个元素。
示例(组合中间操作):
List<User> users = Arrays.asList(
new User("张三", 17),
new User("李四", 22),
new User("王五", 19),
new User("李四", 22)
);
// 筛选成年用户 → 去重 → 提取姓名 → 跳过前 1 个 → 限制 1 个
users.stream()
.filter(u -> u.getAge() >= 18) // 成年:李四、王五、李四
.distinct() // 去重:李四、王五
.map(User::getName) // 提取姓名:"李四"、"王五"
.skip(1) // 跳过第一个:"王五"
.limit(1) // 保留 1 个:"王五"
.forEach(System.out::println); // 输出:王五
3. 第三步:终端操作(常用 API)
- 遍历:
forEach(Consumer)(无返回值,直接消费元素); - 收集:
collect(Collector)(转为集合、Map 等,如Collectors.toList()); - 统计:
count()(元素个数)、average()(平均值,仅数值流)、max(Comparator)(最大值); - 判断:
anyMatch(Predicate)(是否存在符合条件的元素)、allMatch(Predicate)(是否所有元素符合)。
示例(终端操作):
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6);
// 1. 收集为集合
List<Integer> evenList = numbers.stream()
.filter(num -> num % 2 == 0)
.collect(Collectors.toList()); // [2,4,6]
// 2. 统计个数
long evenCount = numbers.stream()
.filter(num -> num % 2 == 0)
.count(); // 3
// 3. 判断是否存在大于 5 的元素
boolean hasGt5 = numbers.stream()
.anyMatch(num -> num > 5); // true
// 4. 求最大值
Optional<Integer> max = numbers.stream()
.max(Integer::compare); // 6
四、Stream 的核心价值
- 简化代码:用链式调用替代繁琐的循环、判断,代码行数大幅减少;
- 提高效率:惰性执行 + 并行处理,底层优化(如流水线操作、减少中间集合创建);
- 易维护:声明式编程让逻辑更清晰,可读性、可维护性提升;
- 功能强大:内置丰富的中间 / 终端操作,支持筛选、排序、映射、统计等常见场景。
五、关键注意事项
-
不修改原数据源:所有操作都是 "只读",原始集合 / 数组不会被改变;
-
Stream 不可复用 :终端操作后 Stream 失效,需重新创建(如下方错误示例);
Stream<Integer> stream = numbers.stream().filter(num -> num % 2 == 0); stream.forEach(System.out::println); // 终端操作,stream 失效 stream.count(); // 报错:IllegalStateException(stream 已被消费) -
并行流的线程安全 :并行处理时,若中间操作有状态(如自定义
map中修改外部集合),需保证线程安全(推荐用无状态操作); -
空指针处理 :Stream 不直接处理
null元素,若数据源有null,需提前用filter(Objects::nonNull)过滤。
总结
- 是什么:Java 8 新增的 "元素序列",用于声明式处理数据源,不存储、不修改原数据;
- 核心结构:创建 Stream → 中间操作(链式)→ 终端操作(触发执行);
- 核心特性:惰性执行、并行支持、声明式编程、无状态 / 有状态操作;
- 价值:简化代码、提高效率、易维护,是 Java 集合处理的 "升级方案";
- 使用场景:集合筛选、排序、映射、统计等数据处理场景(替代传统循环)。