Java 8 的流(Stream API)简介

发布于:2025-04-05 ⋅ 阅读:(33) ⋅ 点赞:(0)

Java 8 引入的 Stream API 是一个强大的工具,用于处理集合(如 List、Set)中的元素。它支持各种操作,包括过滤、排序、映射等,并且能够以声明式的方式表达复杂的查询操作。流操作可以是中间操作(返回流以便进一步处理)或终端操作(产生结果或副作用)。此外,Stream API 还支持并行执行,从而利用多核处理器的优势。

Stream 的基本概念


  • 任何提供数据的集合(如 ListSet、数组等)均可作为流的来源。

  • 中间操作
    返回新流对象,支持链式调用,惰性求值。常见操作包括:

    • filter(筛选)
    • map(映射)
    • sorted(排序)
    • distinct(去重)
    • limit(限制数量)
    • skip(跳过元素)
    • flatMap(扁平化映射)
    • peek(调试查看)
  • 终端操作
    触发流处理并生成结果,执行后流被消耗。常见操作包括:

    • forEach(遍历)
    • collect(收集到集合)
    • reduce(聚合)
    • count(统计数量)
    • findFirst/findAny(查找元素)
    • anyMatch/allMatch/noneMatch(匹配验证)

创建 Stream 的方式

  1. 从集合创建

    List<String> list = Arrays.asList("apple", "banana", "pear");
    Stream<String> stream = list.stream();
  2. 从数组创建

    String[] arr = {"apple", "banana", "pear"};
    Stream<String> stream = Arrays.stream(arr);
  3. 生成无限流

    // 迭代生成(0, 1, 2, ...)
    Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1);
    
    // 随机生成
    Stream<Double> randomStream = Stream.generate(Math::random);

中间操作详解

1. 筛选与切片

  • filter:按条件筛选元素

    List<String> filtered = list.stream()
        .filter(s -> s.length() > 3)
        .collect(Collectors.toList());
  • distinct:去重(需重写 equals 和 hashCode

    List<Integer> distinctList = Arrays.asList(1, 2, 2, 3)
        .stream()
        .distinct()
        .collect(Collectors.toList()); // [1, 2, 3]
  • limit:截取前 N 个元素

    List<String> firstTwo = list.stream()
        .limit(2)
        .collect(Collectors.toList());
  • skip:跳过前 N 个元素

    List<String> skipped = list.stream()
        .skip(1)
        .collect(Collectors.toList());

2. 映射与扁平化

  • map:元素类型转换

    List<String> upperCase = list.stream()
        .map(String::toUpperCase)
        .collect(Collectors.toList());
  • flatMap:扁平化嵌套集合

    List<List<Integer>> nestedList = Arrays.asList(
        Arrays.asList(1, 2),
        Arrays.asList(3, 4)
    );
    List<Integer> flatList = nestedList.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList()); // [1, 2, 3, 4]

3. 排序

  • 自然排序

    List<String> sortedList = list.stream()
        .sorted()
        .collect(Collectors.toList());
  • 自定义排序

    List<Employee> sortedEmployees = employees.stream()
        .sorted((e1, e2) -> e2.getAge() - e1.getAge())
        .collect(Collectors.toList());

4. 调试查看

  • peek:遍历元素时执行操作(如打印)
    list.stream()
        .peek(System.out::println)
        .collect(Collectors.toList());

终端操作详解

1. 收集结果

  • 收集到集合

    List<String> listResult = Stream.of("a", "b", "c")
        .collect(Collectors.toList());
    
    Set<String> setResult = Stream.of("apple", "banana", "pear")
        .collect(Collectors.toSet());
  • 分组与分区

    Map<Integer, List<String>> grouped = list.stream()
        .collect(Collectors.groupingBy(s -> s.length()));

2. 聚合操作

  • reduce 求和

    int sum = numbers.stream()
        .reduce(0, (a, b) -> a + b);
  • 拼接字符串

    String joined = Stream.of("a", "b", "c")
        .reduce("", (a, b) -> a + b); // "abc"
  • 无初始值的聚合

    Optional<Integer> max = numbers.stream()
        .reduce(Integer::max);

3. 查找与匹配

  • findFirst:获取第一个元素

    Optional<String> first = list.stream()
        .filter(s -> s.startsWith("a"))
        .findFirst();
  • findAny:获取任意元素(并行流中可能乱序)

    Optional<String> any = list.parallelStream()
        .findAny();
  • max/min:获取极值

    Optional<Integer> maxNumber = numbers.stream()
        .max(Integer::compare);

4. 匹配验证

  • anyMatch:至少一个元素满足条件

    boolean hasEven = numbers.stream()
        .anyMatch(n -> n % 2 == 0);
  • allMatch:所有元素满足条件

    boolean allEven = numbers.stream()
        .allMatch(n -> n % 2 == 0);
  • noneMatch:无元素满足条件

    boolean noEven = numbers.stream()
        .noneMatch(n -> n % 2 == 0);

5. 统计与转换

  • count:统计元素数量

    long count = list.stream()
        .filter(s -> s.length() > 3)
        .count();
  • toArray:转换为数组

    String[] array = list.stream()
        .toArray(String[]::new);
  • 数值统计

    IntSummaryStatistics stats = numbers.stream()
        .mapToInt(Integer::intValue)
        .summaryStatistics();
    System.out.println(stats.getAverage()); // 平均值

6. 遍历操作

  • forEach:执行副作用操作
    list.stream()
        .forEach(System.out::println);

并行流(Parallel Stream)

  • 启用并行流

    List<String> list = Arrays.asList("apple", "banana", "pear");
    list.parallelStream().forEach(System.out::println);
  • 注意事项

    • 并行流可能提高大数据集处理性能。
    • 需确保线程安全性(如避免共享状态修改)。
    • 并行排序(sorted())可能不稳定,需谨慎使用。

注意事项

  1. 中间操作顺序
    逻辑顺序需合理(如先 filter 再 map)。

  2. 对象去重
    使用 distinct() 时需重写 hashCode() 和 equals()

  3. 流复用问题
    终端操作后流被消耗,需重新创建流:

    Stream<String> stream = list.stream();
    stream.forEach(System.out::println); // 首次使用
    stream.forEach(System.out::println); // 报错!流已关闭
  4. 安全获取值
    使用 Optional 的 orElse()orElseGet() 或 orElseThrow() 避免空指针。

总结

Java 8 Stream API 通过声明式编程简化了集合操作,支持链式调用和并行处理。合理使用中间操作(如 filtermap)和终端操作(如 collectreduce),可高效完成数据聚合、过滤及验证。结合并行流可显著提升大数据集处理性能,但需注意线程安全性和操作顺序。


网站公告

今日签到

点亮在社区的每一天
去签到