【集合】Java 8 - Stream API 17种常用操作与案例详解

文章目录

  • [Java8 Stream API 17种常用操作与案例详解](#Java8 Stream API 17种常用操作与案例详解)
    • [1. collect():将流中的元素收集到集合中](#1. collect():将流中的元素收集到集合中)
    • [2. filter():根据条件过滤流中的元素](#2. filter():根据条件过滤流中的元素)
    • [3. map():元素映射为另一个值](#3. map():元素映射为另一个值)
    • [4. forEach():对流中的元素执行操作](#4. forEach():对流中的元素执行操作)
    • [5. flatMap():将流中的元素展开成一个流](#5. flatMap():将流中的元素展开成一个流)
    • [6. reduce():累积操作](#6. reduce():累积操作)
    • [7. distinct():去重](#7. distinct():去重)
    • [8. sorted():排序](#8. sorted():排序)
    • [9. limit():截断流](#9. limit():截断流)
    • [10. skip():跳过前 n 个元素](#10. skip():跳过前 n 个元素)
    • [11. anyMatch() / allMatch() / noneMatch():条件匹配](#11. anyMatch() / allMatch() / noneMatch():条件匹配)
    • [12. findFirst() 和 findAny()](#12. findFirst() 和 findAny())
    • [13. max() / min():获取最大值或最小值](#13. max() / min():获取最大值或最小值)
    • [14. peek():调试流中的元素](#14. peek():调试流中的元素)
    • [15. count():统计流中的元素个数](#15. count():统计流中的元素个数)
    • [16. groupBy():将流中的元素按照指定的条件分组](#16. groupBy():将流中的元素按照指定的条件分组)
    • [17. partitioningBy():将流中的元素按照指定的条件分成两个部分。](#17. partitioningBy():将流中的元素按照指定的条件分成两个部分。)
  • 总结补充

Java8 Stream API 17种常用操作与案例详解

在 Java 8 中,Stream API 提供了一种高效、简洁的数据处理方式,特别适合对集合、数组等数据源进行操作。Stream 通过函数式编程风格,支持链式调用,避免了传统 for 循环中复杂的代码逻辑。本文将详细介绍 17 种常用 Stream 操作方法,并通过示例代码帮助大家理解如何应用于实际开发中。


1. collect():将流中的元素收集到集合中

collect() 方法用于将流中的数据收集到集合、映射等数据结构中,非常常见。

示例

java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// 收集名字长度大于 3 的元素到 List 集合
List<String> filteredNames = names.stream()
                                  .filter(name -> name.length() > 3)
                                  .collect(Collectors.toList());
System.out.println(filteredNames); // Output: [Alice, Charlie, David]

理解要点
collect() 是终止操作,它将流中的元素重新汇总到新的集合中。这里的 Collectors.toList() 是一种常见用法,用于收集元素到 List 集合中。


2. filter():根据条件过滤流中的元素

filter() 用于筛选出满足特定条件的元素,它返回一个新的流,流中的元素都满足过滤条件。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 过滤出偶数
List<Integer> evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .collect(Collectors.toList());
System.out.println(evenNumbers); // Output: [2, 4]

理解要点

这里 n -> n % 2 == 0 是一个 Lambda 表达式,表示只保留能被 2 整除的元素。filter() 不会修改原数据,而是返回一个新的流。


3. map():元素映射为另一个值

map() 会对流中的每个元素执行操作,并将结果映射成一个新的流。

示例

java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 转换为大写
List<String> upperCaseNames = names.stream()
                                   .map(String::toUpperCase)
                                   .collect(Collectors.toList());
System.out.println(upperCaseNames); // Output: [ALICE, BOB, CHARLIE]

理解要点

  • map() 接受一个函数作为参数,将流中的每个元素转换为新形式。
  • String::toUpperCase 是方法引用,等同于 name -> name.toUpperCase()

4. forEach():对流中的元素执行操作

forEach() 是终止操作,用于遍历流中的元素并执行指定的操作。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 输出每个元素
numbers.stream().forEach(System.out::println);
// Output: 1 2 3 4 5

理解要点

  • System.out::println 是方法引用,等同于 n -> System.out.println(n)
  • forEach() 不返回新流,只执行操作。

5. flatMap():将流中的元素展开成一个流

flatMap() 用于处理嵌套集合(比如 List),它将每个元素的流展开,并合并成一个新的流。

示例

java 复制代码
List<List<Integer>> listOfLists = Arrays.asList(
    Arrays.asList(1, 2, 3), 
    Arrays.asList(4, 5), 
    Arrays.asList(6, 7, 8)
);

// 合并多个列表为一个流
List<Integer> mergedList = listOfLists.stream()
                                      .flatMap(List::stream)
                                      .collect(Collectors.toList());
System.out.println(mergedList); // Output: [1, 2, 3, 4, 5, 6, 7, 8]

理解要点

  • flatMap() 的作用是 "摊平" 元素,比如将多个小集合合并成一个大集合。
  • 这里 List::stream 表示将每个子集合转换为流。

6. reduce():累积操作

reduce() 用于将流中的元素进行聚合操作,例如求和、求最大值等。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 求和
int sum = numbers.stream()
                 .reduce(0, Integer::sum);
System.out.println(sum); // Output: 15

理解要点

  • reduce 需要一个初始值(这里是 0),一个二元操作(Integer::sum)。
  • 操作会从初始值开始累加流中的元素。

7. distinct():去重

distinct() 方法用于去掉流中的重复元素,最终返回一个去重后的流。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4);

// 去重
List<Integer> distinctNumbers = numbers.stream()
                                       .distinct()
                                       .collect(Collectors.toList());
System.out.println(distinctNumbers); // Output: [1, 2, 3, 4]

理解要点
distinct() 会基于元素的 equals()hashCode() 方法判断是否重复。


8. sorted():排序

sorted() 可以对流中的元素进行排序,支持自然排序和自定义排序。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);

// 升序排序
List<Integer> sortedNumbers = numbers.stream()
                                     .sorted()	//Comparator.comparing()
                                     .collect(Collectors.toList());
System.out.println(sortedNumbers); // Output: [1, 2, 3, 4, 5]

理解要点

  • 默认情况下,sorted() 使用自然排序(升序)。
  • 如果需要自定义排序,可以传入比较器。

9. limit():截断流

limit() 用于获取流中的前 n 个元素。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

// 只获取前 3 个元素
List<Integer> limitedNumbers = numbers.stream()
                                      .limit(3)
                                      .collect(Collectors.toList());
System.out.println(limitedNumbers); // Output: [1, 2, 3]

实际场景

例如分页功能中,可以结合 skip() 实现数据的分页查询。


10. skip():跳过前 n 个元素

skip() 用于跳过流中的前 n 个元素,返回剩余元素的流。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

// 跳过前 4 个元素
List<Integer> skippedNumbers = numbers.stream()
                                      .skip(4)
                                      .collect(Collectors.toList());
System.out.println(skippedNumbers); // Output: [5, 6, 7]

结合 limit()

java 复制代码
// 获取第 4 到第 6 个元素
List<Integer> subList = numbers.stream()
                               .skip(3)
                               .limit(3)
                               .collect(Collectors.toList());
System.out.println(subList); // Output: [4, 5, 6]

实际场景

跳过已处理数据,优化批量处理的效率。


11. anyMatch() / allMatch() / noneMatch():条件匹配

这三个方法用于判断流中的元素是否符合条件:

  • anyMatch():是否有任意一个元素满足条件。
  • allMatch():所有元素都满足条件。
  • noneMatch():没有任何元素满足条件。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 是否存在大于 4 的元素
boolean anyMatch = numbers.stream().anyMatch(n -> n > 4);
System.out.println(anyMatch); // Output: true

// 是否所有元素都小于 6
boolean allMatch = numbers.stream().allMatch(n -> n < 6);
System.out.println(allMatch); // Output: true

// 是否没有大于 5 的元素
boolean noneMatch = numbers.stream().noneMatch(n -> n > 5);
System.out.println(noneMatch); // Output: true

实际场景

  • 数据校验,例如用户输入是否符合条件。
  • 筛选判断,例如是否存在符合条件的订单。

12. findFirst() 和 findAny()

  • findFirst():返回流中的第一个元素,通常在顺序流中使用。
  • findAny():返回流中的任意一个元素,适合并行流操作,效率更高。
java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 使用 findFirst 方法查找第一个元素
Optional<Integer> first = numbers.stream().findFirst();

// 使用 findAny 方法查找任意一个元素
Optional<Integer> any = numbers.stream().findAny();

// 输出结果
System.out.println("First: " + first.orElse(null)); // Output: 1
System.out.println("Any: " + any.orElse(null));     // Output: 1 或其他任意元素
    

特别说明:

  • 顺序流 中,findAny() 的行为与 findFirst() 相似,通常会返回第一个元素。
  • 并行流 中,findAny() 可能会返回流中任意位置的元素,以提高性能。

13. max() / min():获取最大值或最小值

max()min() 用于根据比较器找出流中的最大或最小元素。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 获取最大值
Optional<Integer> max = numbers.stream().max(Integer::compareTo);
System.out.println(max.get()); // Output: 5

// 获取最小值
Optional<Integer> min = numbers.stream().min(Integer::compareTo);
System.out.println(min.get()); // Output: 1

理解要点

  • max()min() 返回 Optional 对象,需使用 .get() 获取值。
  • 可以使用自定义比较器实现复杂比较逻辑。

14. peek():调试流中的元素

peek() 用于对流中的每个元素执行操作,但不会中断流的操作。适合用来调试。

示例

java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 打印调试信息
List<String> filteredNames = names.stream()
                                  .peek(name -> System.out.println("Before filter: " + name))
                                  .filter(name -> name.length() > 3)
                                  .peek(name -> System.out.println("After filter: " + name))
                                  .collect(Collectors.toList());
System.out.println(filteredNames);

输出

Before filter: Alice  
After filter: Alice  
Before filter: Bob  
Before filter: Charlie  
After filter: Charlie  
[Alice, Charlie]

理解要点
peek() 通常用于调试,打印中间状态,帮助排查问题。


15. count():统计流中的元素个数

count() 是一个终止操作,用于统计流中元素的个数。

示例

java 复制代码
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// 统计名字长度大于 3 的元素个数
long count = names.stream()
                  .filter(name -> name.length() > 3)
                  .count();
System.out.println(count); // Output: 2

实际场景

数据统计,比如计算符合条件的记录数量。


16. groupBy():将流中的元素按照指定的条件分组

sorted(Comparator) 支持根据自定义逻辑对流中的元素进行排序。

示例

java 复制代码
 List<String> words = Arrays.asList("dog", "cat", "elephant", "rat", "ant");

// 按字符串长度分组
Map<Integer, List<String>> groupedByLength = words.stream()
    .collect(Collectors.groupingBy(String::length));

System.out.println(groupedByLength); 
// 输出: {3=[dog, cat, rat, ant], 8=[elephant]}

理解要点

  • Collectors.groupingBy() 返回值作为键。

17. partitioningBy():将流中的元素按照指定的条件分成两个部分。

sorted(Comparator) 支持根据自定义逻辑对流中的元素进行排序。

示例

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

// 根据是否为偶数进行分区
Map<Boolean, List<Integer>> partitionedByEvenOdd = numbers.stream()
    .collect(Collectors.partitioningBy(num -> num % 2 == 0));

System.out.println(partitionedByEvenOdd); 
// 输出: {false=[1, 3, 5, 7, 9], true=[2, 4, 6, 8]}

分区结合统计信息:

java 复制代码
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

// 分区后统计每组的元素数量
Map<Boolean, Long> countByEvenOdd = numbers.stream()
.collect(Collectors.partitioningBy(num -> num % 2 == 0, Collectors.counting()));

System.out.println(countByEvenOdd); 
// 输出: {false=5, true=4}

总结补充

通过以上 17 个常用操作,我们可以看到 Stream API 在数据处理方面提供了强大的功能。总结一些常见的使用场景:

  1. 数据过滤与筛选filter()distinct()limit()
  2. 数据转换与聚合map()flatMap()reduce()
  3. 数据统计与校验count()allMatch()anyMatch()
  4. 调试与排序peek()sorted()max()min()

合理使用 Stream API,能够让代码更加简洁、可读性更强,同时提高开发效率。希望这篇文章对大家有帮助!!👍★(疯狂暗示)

博客主页: 总是学不会.

相关推荐
顽石九变4 分钟前
【SpringBoo3】SpringBoot项目Web拦截器使用
spring boot·后端
小韩学长yyds5 分钟前
Java调用第三方HTTP接口:从入门到实战
java·开发语言·http
苏十八7 分钟前
JavaEE Servlet02
java·服务器·网络·java-ee·json
爬菜12 分钟前
异常(5)
java
苹果酱056736 分钟前
Golang的数据库备份与恢复
java·vue.js·spring boot·mysql·课程设计
青石路1 小时前
经由同个文件多次压缩的文件MD5都不一样问题排查,感慨AI的强大!
java·后端
木头没有瓜1 小时前
Mybatis集合嵌套查询,三级嵌套
java·tomcat·mybatis
知行021 小时前
23中设计模式之观察者模式
java·观察者模式·设计模式
RainbowSea1 小时前
5. MySQL 存储引擎(详解说明)
数据库·后端·mysql
迷路的小犀牛1 小时前
JAVA编程【设计模式之工厂模式】
java·开发语言·设计模式