目录
一、基础概念
1. 流的三要素
2. 流的特点
二、创建 Stream(数据源)
1. 从集合创建(最常用)
2. 从数组创建
3. 直接创建空流 / 指定元素流
4. 无限流(生成 / 迭代)
三、中间操作(Intermediate)
1. 常用无状态操作(不依赖前后元素)
filter 过滤
map 映射(类型转换 / 字段提取)
flatMap 扁平化映射(拆分层级)
peek 查看 / 调试流
2. 常用有状态操作(依赖全部元素 / 顺序)
distinct 去重
sorted 排序
limit /skip 截取 / 跳过
四、终端操作(Terminal)
1. forEach /forEachOrdered 遍历
2. collect 收集(最核心)
① 转为 List / Set / 数组
② 拼接字符串 joining
③ 分组 groupingBy(类似 SQL group by)
④ 分区 partitioningBy(二分区:true/false)
⑤ 聚合统计(count、max、min、avg、sum)
3. 匹配操作(返回 boolean)
4. 查找操作
5. 规约 reduce(聚合计算,自定义累加)
五、数值流(IntStream / LongStream / DoubleStream)
1. 转换数值流
2. 范围创建数值流
3. 数值便捷计算
六、并行流 parallelStream
1. 开启方式
2. 原理
3. 注意事项(坑)
七、完整实战示例(传统循环 VS 流式)
传统 for 循环
Stream 流式写法(一行链式)
八、常见避坑总结
九、Java 9+ 新增增强(拓展)
Java 8 引入 Stream 流,用于集合 / 数组的链式、函数式数据处理,替代传统循环遍历,代码更简洁、可读性强,支持并行计算。
核心定位:不是数据结构,是数据的「处理管道」,不存储数据,只操作数据源。
一、基础概念
1. 流的三要素
2. 流的特点
- 惰性求值:中间操作直到终端调用才执行
- 单向不可逆:流一旦终端消费,不能重复使用
- 不修改原数据源:所有操作返回新结果,原集合不变
- 支持并行流:简单切换即可利用多线程
二、创建 Stream(数据源)
1. 从集合创建(最常用)
List<String> list = Arrays.asList("A", "B", "C");
// 顺序流
Stream<String> stream = list.stream();
// 并行流
Stream<String> parallelStream = list.parallelStream();
2. 从数组创建
String[] arr = {"1", "2", "3"};
Stream<String> stream = Arrays.stream(arr);
3. 直接创建空流 / 指定元素流
// 空流
Stream<String> empty = Stream.empty();
// 可变参数创建流
Stream<Integer> numStream = Stream.of(1, 2, 3, 4);
4. 无限流(生成 / 迭代)
常用于造测试数据,必须配合 limit 截断,否则死循环
// 迭代:从0开始,每次+2
Stream.iterate(0, n -> n + 2).limit(5).forEach(System.out::println);
// 生成:随机数
Stream.generate(Math::random).limit(3).forEach(System.out::println);
三、中间操作(Intermediate)
返回 Stream,可链式拼接,延迟执行,分为:无状态、有状态。
1. 常用无状态操作(不依赖前后元素)
filter 过滤
筛选符合条件元素,参数 Predicate 断言
List<Integer> nums = Arrays.asList(1,2,3,4,5,6);
nums.stream()
.filter(n -> n > 3) // 保留大于3的数
.forEach(System.out::println);
map 映射(类型转换 / 字段提取)
一对一转换,参数 Function
// 数字转字符串
nums.stream().map(String::valueOf).forEach(System.out::println);
// 实体类提取字段(示例)
class User { String name; }
List<User> userList = new ArrayList<>();
userList.stream().map(User::getName).forEach(System.out::println);
flatMap 扁平化映射(拆分层级)
一对多,把流中的集合 / 数组拆解为单个元素,解决嵌套集合
List<List<String>> nested = Arrays.asList(
Arrays.asList("a","b"),
Arrays.asList("c","d")
);
// 扁平化:两层集合 → 单层流
nested.stream()
.flatMap(Collection::stream)
.forEach(System.out::println);
peek 查看 / 调试流
遍历元素,不改变流,多用于打印日志、调试
nums.stream()
.peek(n -> System.out.println("原始:" + n))
.filter(n -> n % 2 == 0)
.peek(n -> System.out.println("过滤后:" + n))
.count(); // 终端触发执行
2. 常用有状态操作(依赖全部元素 / 顺序)
distinct 去重
基于 equals() + hashCode() 去重
Arrays.asList(1,2,2,3,3,3).stream()
.distinct()
.forEach(System.out::println);
sorted 排序
- 无参:自然排序(实现 Comparable)
- 有参:自定义 Comparator 比较器
// 自然升序
nums.stream().sorted().forEach(System.out::println);
// 自定义降序
nums.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
limit /skip 截取 / 跳过
- limit(n):取前 n 个元素
- skip(n):跳过前 n 个元素
// 跳过前2个,取后3个
nums.stream().skip(2).limit(3).forEach(System.out::println);
四、终端操作(Terminal)
触发流执行,流关闭,不能继续链式调用,分为:遍历、收集、匹配、聚合、规约等。
1. forEach /forEachOrdered 遍历
- forEach:顺序流有序,并行流无序
- forEachOrdered:并行流也保证遍历顺序
nums.stream().forEach(System.out::println);
nums.parallelStream().forEachOrdered(System.out::println);
2. collect 收集(最核心)
将流转回 集合、字符串、分组、分区等,Collectors 工具类提供大量静态方法。
① 转为 List / Set / 数组
// 转 List
List<Integer> list = nums.stream().collect(Collectors.toList());
// 转 Set(自动去重)
Set<Integer> set = nums.stream().collect(Collectors.toSet());
// 转数组
Integer[] array = nums.stream().toArray(Integer[]::new);
② 拼接字符串 joining
List<String> strs = Arrays.asList("Java","Stream","Demo");
// 直接拼接
String s1 = strs.stream().collect(Collectors.joining());
// 分隔符拼接
String s2 = strs.stream().collect(Collectors.joining(","));
// 分隔符 + 前缀 + 后缀
String s3 = strs.stream().collect(Collectors.joining(",", "[", "]"));
③ 分组 groupingBy(类似 SQL group by)
List<User> userList = Arrays.asList(
new User("张三", 20),
new User("李四", 22),
new User("王五", 20)
);
// 按年龄分组 key:年龄 value:同年龄用户集合
Map<Integer, List<User>> group = userList.stream()
.collect(Collectors.groupingBy(User::getAge));
④ 分区 partitioningBy(二分区:true/false)
只能分成两组,返回 Map<Boolean, List<T>>
// 分区:年龄>=20 / <20
Map<Boolean, List<User>> part = userList.stream()
.collect(Collectors.partitioningBy(u -> u.getAge() >= 20));
⑤ 聚合统计(count、max、min、avg、sum)
// 一次性统计:数量、总和、最大、最小、平均值
IntSummaryStatistics stat = nums.stream()
.collect(Collectors.summarizingInt(Integer::intValue));
stat.getCount();
stat.getSum();
stat.getMax();
3. 匹配操作(返回 boolean)
// allMatch:全部满足
boolean all = nums.stream().allMatch(n -> n > 0);
// anyMatch:任意一个满足
boolean any = nums.stream().anyMatch(n -> n == 3);
// noneMatch:全部不满足
boolean none = nums.stream().noneMatch(n -> n < 0);
4. 查找操作
// findFirst:获取第一个元素(顺序流稳定)
Optional<Integer> first = nums.stream().findFirst();
// findAny:获取任意元素(并行流效率更高)
Optional<Integer> anyEle = nums.parallelStream().findAny();
注意:返回 Optional,防止空指针。
5. 规约 reduce(聚合计算,自定义累加)
把流中元素反复结合得到一个值,常用于求和、求积、拼接。
List<Integer> numList = Arrays.asList(1,2,3,4);
// 1. 无初始值:返回 Optional
Optional<Integer> sum1 = numList.stream().reduce(Integer::sum);
// 2. 有初始值:直接返回结果(不会空)
Integer sum2 = numList.stream().reduce(0, Integer::sum);
// 自定义累加逻辑
Integer total = numList.stream().reduce(0, (a, b) -> a + b * 2);
五、数值流(IntStream / LongStream / DoubleStream)
普通 Stream<Integer> 存在自动装箱 / 拆箱损耗,Java 提供专用数值流提升性能。
1. 转换数值流
List<Integer> list = Arrays.asList(1,2,3);
// 转 IntStream
IntStream intStream = list.stream().mapToInt(Integer::intValue);
// 转回包装流
Stream<Integer> stream = intStream.boxed();
2. 范围创建数值流
// [1,5] 闭区间
IntStream.rangeClosed(1,5).forEach(System.out::println);
// [1,5) 左闭右开
IntStream.range(1,5).forEach(System.out::println);
3. 数值便捷计算
int sum = intStream.sum();
int max = intStream.max().getAsInt();
double avg = intStream.average().getAsDouble();
六、并行流 parallelStream
1. 开启方式
// 方式1:集合直接调用
list.parallelStream();
// 方式2:顺序流转并行
list.stream().parallel();
2. 原理
底层基于 Fork/Join 框架,多线程拆分任务并行执行,大数据集提升明显。
3. 注意事项(坑)
七、完整实战示例(传统循环 VS 流式)
需求:过滤偶数 → 平方 → 去重 → 收集为 List
传统 for 循环
List<Integer> source = Arrays.asList(1,2,2,3,4,4,5);
List<Integer> result = new ArrayList<>();
for (Integer n : source) {
if (n % 2 == 0) {
int square = n * n;
if (!result.contains(square)) {
result.add(square);
}
}
}
Stream 流式写法(一行链式)
List<Integer> result = source.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.distinct()
.collect(Collectors.toList());




