目录
一、Stream 核心概念解析
1.1 什么是流(Stream)?
-
数据渠道:不存储数据,只负责传输
-
函数式操作:支持链式函数编程
-
惰性求值:中间操作延迟执行,终止操作触发计算
-
不可复用:终止操作后流即关闭
1.2 流 vs 集合
特性 | 集合(Collection) | 流(Stream) |
---|---|---|
存储 | 存储所有元素 | 无存储 |
数据结构 | 具体数据结构(List等) | 抽象计算管道 |
操作方式 | 外部迭代(for-each) | 内部迭代(自动遍历) |
数据处理 | 立即计算 | 延迟计算 |
数据修改 | 支持增删改 | 只读操作 |
二、流操作三阶段全流程
2.1 流生命周期
2.2 操作类型对比
操作类型 | 特点 | 示例方法 |
---|---|---|
中间操作 | 返回新流,延迟执行 | filter(), map(), sorted() |
终止操作 | 触发计算,关闭流 | forEach(), collect(), reduce() |
三、流创建全方式详解
3.1 基础创建方式
// 集合创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();
// 数组创建
String[] array = {"a", "b", "c"};
Stream<String> stream2 = Arrays.stream(array);
// 直接创建
Stream<String> stream3 = Stream.of("a", "b", "c");
// 文件创建
try (Stream<String> lines = Files.lines(Paths.get("data.txt"))) {
lines.forEach(System.out::println);
}
3.2 高级生成方式
// 无限流
Stream<Integer> infinite1 = Stream.iterate(0, n -> n + 2);
Stream<Double> infinite2 = Stream.generate(Math::random);
// 空流
Stream<String> emptyStream = Stream.empty();
// 合并流
Stream<String> merged = Stream.concat(stream1, stream2);
// 基本类型流
IntStream intStream = IntStream.range(1, 100);
四、中间操作实战技巧
4.1 过滤操作
List<User> users = getUserList();
// 多条件过滤
users.stream()
.filter(u -> u.getAge() > 18)
.filter(u -> u.getGender() == Gender.FEMALE)
.filter(u -> u.getCity().equals("Shanghai"));
4.2 映射操作
// 提取属性
List<String> names = users.stream()
.map(User::getName)
.collect(Collectors.toList());
// 扁平化处理
List<String> words = lines.stream()
.flatMap(line -> Arrays.stream(line.split(" ")))
.collect(Collectors.toList());
4.3 排序与去重
// 多字段排序
users.stream()
.sorted(Comparator.comparing(User::getDepartment)
.thenComparing(User::getSalary))
.distinct();
五、终止操作高阶应用
5.1 聚合统计
// 综合统计
IntSummaryStatistics stats = users.stream()
.mapToInt(User::getAge)
.summaryStatistics();
System.out.println("平均年龄: " + stats.getAverage());
System.out.println("最大年龄: " + stats.getMax());
// 分组统计
Map<Department, Long> countByDept = users.stream()
.collect(Collectors.groupingBy(User::getDepartment,
Collectors.counting()));
5.2 归约操作
// 字符串拼接
String joined = users.stream()
.map(User::getName)
.collect(Collectors.joining(", ", "[", "]"));
// 自定义归约
Optional<Integer> totalAge = users.stream()
.map(User::getAge)
.reduce(Integer::sum);
六、并行流性能优化
6.1 并行流使用
// 基础并行
long count = users.parallelStream()
.filter(u -> u.getSalary() > 10000)
.count();
// 注意线程安全
ConcurrentHashMap<Department, List<User>> map = users.parallelStream()
.collect(Collectors.groupingByConcurrent(User::getDepartment));
6.2 性能优化建议
数据规模:推荐N > 10000时使用
操作成本:单个元素处理时间越长收益越大
避免共享状态:保持无状态操作
正确数据结构:使用ArrayList而非LinkedList
七、实战案例集锦
7.1 案例一:数据转换
// List转Map(处理重复key)
Map<String, User> userMap = users.stream()
.collect(Collectors.toMap(
User::getId,
Function.identity(),
(oldVal, newVal) -> newVal));
7.2 案例二:多层分组
// 二级分组统计
Map<Department, Map<Gender, Long>> report = users.stream()
.collect(Collectors.groupingBy(User::getDepartment,
Collectors.groupingBy(User::getGender,
Collectors.counting())));
7.3 案例三:查找优化
// 快速查找匹配项
Optional<User> user = users.stream()
.filter(u -> u.getId().equals("123"))
.findAny()
.or(() -> searchFromRemote("123"));
八、常见问题与解决方案
8.1 流重用问题
// 错误示例
Stream<User> stream = users.stream();
stream.filter(...);
stream.map(...); // 抛出IllegalStateException
// 正确做法:链式调用
users.stream()
.filter(...)
.map(...);
8.2 空指针处理
// 安全处理null
List<String> names = users.stream()
.map(u -> Optional.ofNullable(u.getName()).orElse(""))
.collect(Collectors.toList());
九、基础使用注意事项
1. 流不可重用
// 错误示例
Stream<String> stream = list.stream();
stream.filter(s -> s.length()>3);
stream.map(String::toUpperCase); // 抛出 IllegalStateException
// 正确做法:链式调用
list.stream()
.filter(s -> s.length()>3)
.map(String::toUpperCase);
2. 避免副作用
// 错误示例(修改外部状态)
List<String> result = new ArrayList<>();
stream.forEach(s -> result.add(s)); // 可能引发线程安全问题
// 正确做法:使用 collect
List<String> result = stream.collect(Collectors.toList());
十、性能优化要点
1. 中间操作顺序
// 低效顺序(先 map 后 filter)
stream.map(expensiveOperation)
.filter(...);
// 优化顺序(先 filter 后 map)
stream.filter(...)
.map(expensiveOperation);
2. 谨慎使用并行流
适合场景:数据量 > 1万 + 高计算成本操作
避免场景:IO 密集操作、共享状态修改
// 正确使用示例
List<Integer> squares = numbers.parallelStream()
.map(n -> n * n)
.collect(Collectors.toList());
十一、代码健壮性保障
1. 空指针防护
// 安全处理可能为 null 的流元素
list.stream()
.map(obj -> Optional.ofNullable(obj.getName()).orElse(""))
.collect(Collectors.toList());
2. 无限流控制
// 必须添加限制条件
Stream.iterate(0, n -> n + 1)
.limit(100) // 必须限制
.forEach(System.out::println);
十二、代码可维护性建议
1. 控制链长度
// 建议不超过 5 个操作步骤
stream.filter(...)
.map(...)
.sorted(...)
.distinct()
.limit(...)
.collect(...);
2. 优先使用方法引用
// 更简洁易读
list.stream()
.map(String::toLowerCase) // 优于 s -> s.toLowerCase()
.collect(Collectors.toList());
十三、调试与测试技巧
1. 使用 peek() 调试
list.stream()
.peek(System.out::println) // 查看中间结果
.filter(...)
.peek(e -> logger.debug("Filtered: {}", e))
.collect(...);
2. 单元测试验证
@Test
void testStreamLogic() {
List<Integer> input = Arrays.asList(1,2,3);
List<Integer> result = input.stream()
.filter(n -> n%2==0)
.collect(Collectors.toList());
assertThat(result).containsExactly(2);
}
十三、高级注意事项
1. 自定义 Spliterator
处理特殊数据结构时实现高效分割
需正确实现 trySplit() 和 estimateSize()
2. 短路操作优化
// 找到第一个匹配项即终止
Optional<Integer> first = stream.filter(...).findFirst();
十四、总结
Stream 是Java 8+的高效数据处理抽象,不存储数据,通过链式函数操作集合。关键特性:
-
惰性求值:中间操作(filter/map)延迟执行,终止操作(collect/forEach)触发计算
-
不可复用:终止操作后流即关闭
-
并行处理:parallelStream() 利用多核,需数据量大且无状态
常用操作:过滤(filter)、映射(map)、归约(reduce)、收集(collect)
注意事项:避免副作用、优先方法引用、空值用Optional防护、先过滤后映射优化性能。适用于集合处理、数据转换和统计分析,提升代码简洁性与执行效率。