Java Stream API 实用手册
Stream API 是 Java 8 引入的函数式数据处理框架。它不是 I/O 流,而是对集合的一种声明式处理管道。
创建 Stream
java
// 从集合
List<String> list = List.of("a", "b", "c");
Stream<String> s1 = list.stream();
// 从数组
String[] arr = {"a", "b", "c"};
Stream<String> s3 = Arrays.stream(arr);
// 直接创建
Stream<Integer> s5 = Stream.iterate(0, n -> n + 2).limit(10);
Stream<Double> s6 = Stream.generate(Math::random).limit(5);
// 无限流 + takeWhile
Stream.iterate(1, n -> n * 2)
.takeWhile(n -> n < 1000)
.forEach(System.out::println); // 1,2,4,8,...512常用中间操作
map vs flatMap
java
// map:一对一
List<String> names = users.stream().map(User::getName).toList();
// flatMap:一对多拍平
List<List<Integer>> nested = List.of(List.of(1, 2), List.of(3, 4));
List<Integer> flat = nested.stream()
.flatMap(List::stream)
.toList(); // [1, 2, 3, 4]sorted
java
List<User> sorted = users.stream()
.sorted(Comparator
.comparing(User::getAge).reversed()
.thenComparing(User::getName))
.toList();强大的 Collectors
分组
java
Map<String, List<User>> byDept = users.stream()
.collect(Collectors.groupingBy(User::getDept));
Map<String, Long> countByDept = users.stream()
.collect(Collectors.groupingBy(User::getDept, Collectors.counting()));
// 多级分组
Map<String, Map<String, List<User>>> multi = users.stream()
.collect(Collectors.groupingBy(
User::getDept,
Collectors.groupingBy(User::getLevel)));分区
java
Map<Boolean, List<User>> partition = users.stream()
.collect(Collectors.partitioningBy(u -> u.getAge() >= 18));toMap 及其陷阱
java
// 有重复 key 时需要合并函数!
Map<String, User> byName = users.stream()
.collect(Collectors.toMap(
User::getName,
Function.identity(),
(existing, replacement) -> existing));拼接字符串
java
String csv = users.stream()
.map(User::getName)
.collect(Collectors.joining(", ", "[", "]"));
// [Alice, Bob, Charlie]常见陷阱
1. 流只能消费一次
java
Stream<Integer> stream = Stream.of(1, 2, 3);
stream.forEach(System.out::println);
stream.forEach(System.out::println); // IllegalStateException!2. 中间操作是惰性的
java
// filter 里的 lambda 不会立即执行,只有遇到终端操作才会执行3. 并行流不一定更快
小数据量或简单操作时,线程切换开销可能大于并行收益。适合用 parallelStream 的场景:数据量大、单元素处理开销大、无共享状态。
4. 不要在 forEach 里修改外部状态
java
// 错误
List<String> results = new ArrayList<>();
stream.forEach(s -> results.add(transform(s))); // 并行流下不安全
// 正确
List<String> results = stream.map(this::transform).toList();小结
Stream API 的核心思想是声明式数据处理。掌握 filter/map/flatMap 组合、Collectors 家族和 reduce,就能用极少的代码完成复杂的数据处理。记住流是一次性的、中间操作是惰性的、并行流要谨慎使用。