Java Stream 进阶:去重计算、CollectToMap 冲突解决与常用操作

553 阅读2分钟

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 指定冲突处理策略:

  1. 覆盖旧值:保留最后一次出现的 Value

    Map<String, Integer> map = list.stream()
        .collect(Collectors.toMap(
            s -> s,
            s -> s.length(),
            (oldVal, newVal) -> newVal  // 选择新值
        ));
    
  2. 保留旧值:保留第一次出现的 Value

    (oldVal, newVal) -> oldVal
    
  3. 合并为集合:将相同 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 操作整合

  1. 过滤与转换

    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());
    
  2. 排序与限制

    List<Integer> sorted = numbers.stream()
        .sorted(Comparator.reverseOrder())  // 降序
        .limit(3)                           // 取前3个
        .collect(Collectors.toList());
    
  3. 分组与统计

    Map<String, Long> countMap = list.stream()
        .collect(Collectors.groupingBy(
            s -> s.startsWith("a") ? "A组" : "其他组",
            Collectors.counting()
        ));
    
  4. 扁平化处理(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]
    
  5. 并行流加速

    long count = numbers.parallelStream()
        .filter(n -> n > 10)
        .count();
    

四、注意事项

  1. 并行流线程安全:确保操作无状态且不依赖外部变量。
  2. 避免副作用:不要在 map()filter() 中修改外部数据。
  3. 性能权衡:小数据量时,并行流可能因线程开销反而更慢。