Stream 的映射、排序、查找、规约
map:映射(重点)
Stream 映射(Mapping)操作用于转换流中的元素,将元素从一种形式转换为另一种形式。将元素通过指定的函数进行转换,生成新的流。
java
// 字符串转大写
List<String> words = Arrays.asList("apple", "banana", "cherry");
words.stream()
.map(String::toUpperCase)
.forEach(System.err::println) ;
// 结果: ["APPLE", "BANANA", "CHERRY"]
// 数学计算
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squares = numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
// 结果: [1, 4, 9, 16, 25]sorted:排序
Stream 排序操作用于对流中的元素进行排序。Java Stream API 提供了灵活的排序方法,支持自然排序和自定义排序。使用元素的自然顺序进行排序(元素必须实现 Comparable 接口)。
1、sorted() - 自然排序
java
// 数字自然排序(升序)
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3);
List<Integer> sortedNumbers = numbers.stream()
.sorted()
.collect(Collectors.toList());
// 结果: [1, 2, 3, 5, 8, 9]
// 字符串自然排序(字典序)
List<String> words = Arrays.asList("banana", "apple", "cherry", "date");
List<String> sortedWords = words.stream()
.sorted()
.collect(Collectors.toList());
// 结果: ["apple", "banana", "cherry", "date"]2、sorted(Comparator) - 自定义排序
使用指定的比较器进行排序。
java
// 数字降序排序
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3);
List<Integer> descendingNumbers = numbers.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
// 结果: [9, 8, 5, 3, 2, 1]
// 字符串按长度排序
List<String> words = Arrays.asList("apple", "kiwi", "banana", "pear");
List<String> byLength = words.stream()
.sorted(Comparator.comparingInt(String::length))
.collect(Collectors.toList());
// 结果: ["kiwi", "pear", "apple", "banana"]查找匹配的多种方法
| 方法 | 使用场景 | 返回值 | 空流结果 | 推荐/替代 |
|---|---|---|---|---|
| anyMatch() | 检查是否存在满足条件的元素 | boolean | false | 检查存在性首选 |
| allMatch() | 检查是否所有元素都满足条件 | boolean | true | 数据验证、完整性检查 |
| noneMatch() | 检查是否没有元素满足条件 | boolean | true | 黑名单检查、安全性验证 |
| findFirst() | 获取第一个元素(保持顺序) | Optional<T> | true | 需要顺序保证时使用 |
| findAny() | 获取任意元素(不关心顺序) | Optional<T> | true | 并行流中性能更好 |
| count() | 统计元素数量 | long | 0 | 数据分析、统计 |
| max() | 查找最大值 | Optional<T> | empty | 需要自定义比较器 |
| min() | 查找最小值 | Optional<T> | empty | 需要自定义比较器 |
1、anyMatch:检查流中是否至少有一个元素满足给定的条件
终端操作,检查流中是否至少有一个元素满足给定的条件
方法签名
java
boolean anyMatch(Predicate<? super T> predicate)返回值
- true:如果至少有一个元素满足条件(Predicate 返回 true)
- false:如果没有任何元素满足条件
- 如果流为空,返回 false
代码示例
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 检查是否有偶数
boolean hasEven = numbers.stream()
.anyMatch(n -> n % 2 == 0);
// 结果: true(因为2、4是偶数)
// 检查是否有大于10的数
boolean hasGreaterThanTen = numbers.stream()
.anyMatch(n -> n > 10);
// 结果: false(所有数都小于等于5)
List<String> words = Arrays.asList("apple", "banana", "cherry", "date");
// 检查是否有以 "a" 开头的单词
boolean startsWithA = words.stream()
.anyMatch(word -> word.startsWith("a"));
// 结果: true("apple")
// 检查是否有长度大于10的单词
boolean hasLongWord = words.stream()
.anyMatch(word -> word.length() > 10);
// 结果: false
// 检查用户是否有任何管理员权限
boolean hasAdminPermission = user.getPermissions().stream()
.anyMatch(permission -> permission.getType() == PermissionType.ADMIN);
// 检查用户是否能访问特定资源
boolean canAccessResource = user.getRoles().stream()
.flatMap(role -> role.getPermissions().stream())
.anyMatch(permission -> permission.getResourceId().equals(resourceId));
// 检查购物车中是否有促销商品
boolean hasPromotionalItem = cart.getItems().stream()
.anyMatch(item -> item.isPromotional() && item.getDiscount() > 0);
// 检查申请单中是否有高风险项目
boolean hasHighRisk = application.getProjects().stream()
.anyMatch(project ->
project.getRiskLevel() == RiskLevel.HIGH ||
project.getBudget() > 1_000_000
);2、allMatch:查流中是否所有元素都满足给定的条件
终端操作,用于检查流中是否所有元素都满足给定的条件。
方法签名
java
boolean allMatch(Predicate<? super T> predicate)返回值
- true:如果所有元素都满足条件(或流为空)
- false:如果至少有一个元素不满足条件
示例代码
java
// 检查是否所有数字都是偶数
List<Integer> numbers = Arrays.asList(2, 4, 6, 8, 10);
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
// 结果: true(所有数字都是偶数)3、noneMatch:检查流中是否没有任何元素满足给定的条件
终端操作,用于检查流中是否没有任何元素满足给定的条件。
方法签名
java
boolean noneMatch(Predicate<? super T> predicate)返回值
- true:如果没有任何元素满足条件(或流为空)
- false:如果至少有一个元素满足条件
示例代码
java
// 检查是否没有奇数
List<Integer> numbers = Arrays.asList(2, 4, 6, 8, 10);
boolean noOddNumbers = numbers.stream().noneMatch(n -> n % 2 != 0);
// 结果: true(所有数字都是偶数,没有奇数)
// 检查是否没有负数
List<Integer> mixedNumbers = Arrays.asList(1, 2, 3, 4, 5);
boolean noNegatives = mixedNumbers.stream().noneMatch(n -> n < 0);
// 结果: true(所有数字都 >= 0)
// 检查是否没有大于10的数字
boolean noneGreaterThanTen = mixedNumbers.stream().noneMatch(n -> n > 10);
// 结果: true4、findFirst:获取流中的第一个元素
终端操作,用于获取流中的第一个元素(如果存在的话)。
方法签名
java
Optional<T> findFirst()返回值
Optional<T>:包含第一个元素的 Optional,如果流为空则返回空的 Optional
示例代码
java
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9);
// 获取第一个元素
Optional<Integer> first = numbers.stream().findFirst();
// 结果: Optional[3] (第一个元素是3)
// 处理Optional结果
first.ifPresent(n -> System.out.println("第一个数字是: " + n));
// 输出: 第一个数字是: 3
// 获取默认值
Integer result = first.orElse(0);
// 结果: 3
List<String> emptyList = Collections.emptyList();
Optional<String> emptyFirst = emptyList.stream().findFirst();
// 结果: Optional.empty5、findAny:获取流中的任意一个元素
终端操作,用于获取流中的任意一个元素(如果存在的话)。
方法签名
java
Optional<T> findAny()返回值
Optional<T>:包含任意元素的 Optional,如果流为空则返回空的 Optional
示例代码
java
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9);
// 获取任意一个元素
Optional<Integer> any = numbers.stream()
.findAny();
// 结果: 通常返回 Optional[3](第一个元素),但不保证
// 处理Optional结果
any.ifPresent(n -> System.out.println("找到一个数字: " + n));
// 可能输出: 找到一个数字: 3
List<String> emptyList = Collections.emptyList();
Optional<String> emptyAny = emptyList.stream()
.findAny();
// 结果: Optional.empty6、count:统计流中元素的数量
终端操作,用于统计流中元素的数量。
方法签名
java
long count()返回值
- long:流中元素的数量
- 如果流为空,返回 0
示例代码
java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 统计元素总数
long count = numbers.stream()
.count();
// 结果: 5
List<String> emptyList = Collections.emptyList();
long emptyCount = emptyList.stream()
.count();
// 结果: 0
// 数组转流计数
int[] array = {1, 2, 3, 4, 5};
long arrayCount = Arrays.stream(array)
.count();
// 结果: 57、max:获取流中最大值的元素
终端操作,用于获取流中最大值的元素。
方法签名
java
Optional<T> max(Comparator<? super T> comparator)返回值
Optional<T>:包含最大元素的 Optional,如果流为空则返回空的 Optional
示例代码
java
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
// 获取最大值
Optional<Integer> maxNumber = numbers.stream()
.max(Integer::compareTo);
// 结果: Optional[9]
// 处理Optional结果
maxNumber.ifPresent(max -> System.out.println("最大值是: " + max));
// 输出: 最大值是: 9
List<Integer> emptyList = Collections.emptyList();
Optional<Integer> emptyMax = emptyList.stream()
.max(Integer::compareTo);
// 结果: Optional.empty8、min:获取流中最小值的元素
终端操作,用于获取流中最小值的元素。
方法签名
java
Optional<T> min(Comparator<? super T> comparator)返回值
Optional<T>:包含最小元素的 Optional,如果流为空则返回空的 Optional
示例代码
java
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6);
// 获取最小值
Optional<Integer> minNumber = numbers.stream()
.min(Integer::compareTo);
// 结果: Optional[1]
// 处理Optional结果
minNumber.ifPresent(min -> System.out.println("最小值是: " + min));
// 输出: 最小值是: 1
List<Integer> emptyList = Collections.emptyList();
Optional<Integer> emptyMin = emptyList.stream()
.min(Integer::compareTo);
// 结果: Optional.empty规约是什么
规约是 Stream API 的核心概念之一,指将流中的元素组合起来,得到一个单一的结果值。
什么是规约?
规约(Reduction)也称为归约,是将一个集合通过某种操作"缩减"为单个值的过程。
生活中的类比
- 求和:1 + 2 + 3 + 4 = 10(4个数规约为1个数)
- 找最大值:[3, 1, 4, 2] → 4(多个数规约为最大值)
- 连接字符串:["a", "b", "c"] → "abc"
常用方法
方法签名
java
// 1. 一个参数:累积函数
Optional<T> reduce(BinaryOperator<T> accumulator)
// 2. 两个参数:初始值 + 累积函数
T reduce(T identity, BinaryOperator<T> accumulator)
// 3. 三个参数:初始值 + 累积函数 + 组合函数(并行流用)
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner)案例
java
// 示例1:求和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 方式1:使用一个参数的reduce
Optional<Integer> sum1 = numbers.stream()
.reduce((a, b) -> a + b);
// 结果: Optional[15]
// 方式2:使用两个参数的reduce(推荐)
Integer sum2 = numbers.stream()
.reduce(0, (a, b) -> a + b);
// 结果: 15
// 方式3:使用方法引用
Integer sum3 = numbers.stream()
.reduce(0, Integer::sum);
// 结果: 15规约的三要素
1. 恒等值(Identity)
- 规约操作的起点值
- 对于加法:0
- 对于乘法:1
- 对于连接字符串:""(空字符串)
- 必须满足:identity op x = x
2. 累积函数(Accumulator)
- 定义如何将元素合并到结果中
- 接收两个参数:当前结果 + 新元素
- 返回新的结果
3. 组合函数(Combiner)
- 用于并行流,合并不同线程的结果
- 顺序流中不会调用
朔风