Java Stream 进阶:去重计算、CollectToMap 冲突解决与常用操作
一、Stream 实现去重、平方根与收集
需求:对一个包含重复元素的集合进行去重,计算每个元素的平方根,最终收集结果。
实现代码:
List<Double> numbers = Arrays.asList(4.0, 9.0, 4.0, 16.0, 25.0, 16.0);
List<Double> result = numbers.stream()
.filter(n -> n >= 0) // 过滤负数(避免平方根异常)
.distinct() // 去重
.map(Math::sqrt) // 计算平方根
.collect(Collectors.toList());
System.out.println(result); // 输出:[2.0, 3.0, 4.0, 5.0]
关键点:
distinct()依赖元素的equals()方法,需确保对象正确重写该方法。- 若处理的是自定义对象,可通过
map()提取唯一标识去重。
二、解决 CollectToMap 的 Key 重复问题
问题复现:
直接使用 Collectors.toMap() 时,若 Key 重复会抛出 IllegalStateException:
List<String> list = Arrays.asList("apple", "banana", "apple");
Map<String, Integer> map = list.stream()
.collect(Collectors.toMap(
s -> s, // Key
s -> s.length() // Value
)); // 抛出异常:Duplicate key "apple"
解决方案:
通过第三个参数 mergeFunction 指定冲突处理策略:
-
覆盖旧值:保留最后一次出现的 Value
Map<String, Integer> map = list.stream() .collect(Collectors.toMap( s -> s, s -> s.length(), (oldVal, newVal) -> newVal // 选择新值 )); -
保留旧值:保留第一次出现的 Value
(oldVal, newVal) -> oldVal -
合并为集合:将相同 Key 的 Value 存入列表
Map<String, List<Integer>> map = list.stream() .collect(Collectors.toMap( s -> s, s -> new ArrayList<>(List.of(s.length())), (list1, list2) -> { list1.addAll(list2); return list1; } ));
三、常用 Stream 操作整合
-
过滤与转换
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 过滤偶数,转换为字符串 List<String> filtered = numbers.stream() .filter(n -> n % 2 == 0) .map(n -> "Number-" + n) .collect(Collectors.toList()); -
排序与限制
List<Integer> sorted = numbers.stream() .sorted(Comparator.reverseOrder()) // 降序 .limit(3) // 取前3个 .collect(Collectors.toList()); -
分组与统计
Map<String, Long> countMap = list.stream() .collect(Collectors.groupingBy( s -> s.startsWith("a") ? "A组" : "其他组", Collectors.counting() )); -
扁平化处理(FlatMap)
List<List<Integer>> nestedList = Arrays.asList( Arrays.asList(1, 2), Arrays.asList(3, 4) ); List<Integer> flattened = nestedList.stream() .flatMap(Collection::stream) .collect(Collectors.toList()); // [1, 2, 3, 4] -
并行流加速
long count = numbers.parallelStream() .filter(n -> n > 10) .count();
四、注意事项
- 并行流线程安全:确保操作无状态且不依赖外部变量。
- 避免副作用:不要在
map()或filter()中修改外部数据。 - 性能权衡:小数据量时,并行流可能因线程开销反而更慢。