Skip to content

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,就能用极少的代码完成复杂的数据处理。记住流是一次性的、中间操作是惰性的、并行流要谨慎使用。

基于 VitePress 构建

总访问量 访客数