You need to enable JavaScript to run this app. Java 8 Stream 如何去除List<Map<String,Object>>中的重复Map元素
优惠活动
大模型
产品
解决方案
定价
更多

Java 8 Stream 如何去除List<Map<String,Object>>中的重复Map元素

现有方案失效的核心原因
  • 第一版编写的代码存在逻辑硬伤:流中每个元素的类型是Map<String, Object>,本身不存在toLowerCase()方法,这段代码根本无法编译运行,属于将Map结构的处理逻辑和字符串的处理逻辑完全混淆。即使去掉这层无效的map转换,直接用HashSet<Map>存储元素,也会因为Map原生的equals判断规则不符合业务对“重复条目”的定义,无法实现预期去重效果。
  • 第二版使用distinct()方法无法生效的本质原因:Stream的distinct()底层完全依赖元素自身的equals()和hashCode()方法判断重复。虽然JDK自带的HashMap实现了内容比对的equals逻辑,但Spring JdbcTemplate返回的结果Map通常存在两个容易踩的坑:
    • 不同结果行的Map key大小写不统一(比如数据库原列返回大写key、自定义列别名返回小写key)
    • 同语义的列值存在类型差异(比如同一数值列的结果,一行返回Long类型、另一行返回BigDecimal类型)
      这种情况下,两个业务上完全等价的Map条目,会因为key大小写、值类型的细微差异,被equals方法判定为不相等,自然无法被distinct识别为重复元素。
可行的正确实现方案

根据不同的业务判定标准,提供两种可直接复用的实现:

  • 方案一:按业务等价规则去重(即只要所有列的取值语义一致就算重复,不纠结key大小写、值的类型差异)
    完全自定义重复判断规则,绕开Map原生equals的限制,用缓存存储每个条目的唯一业务标识做过滤:

    // 线程安全的去重标识缓存,适配并行流场景
    Set<Object> dedupTagCache = ConcurrentHashMap.newKeySet();
    List<Map<String, Object>> dedupList = apptlist.stream()
        .filter(itemMap -> {
            // 自定义生成当前Map的唯一业务标识
            String itemUniqueTag = itemMap.entrySet().stream()
                // key统一转小写,消除大小写差异
                .map(entry -> entry.getKey().toLowerCase() + "=" +
                    // 值统一转字符串序列化,消除同值不同类型的差异
                    (entry.getValue() == null ? "" : entry.getValue().toString()))
                .sorted() // 对拼接片段排序,避免Map遍历顺序不同导致标识不一致
                .collect(Collectors.joining("|"));
            // 标识成功加入缓存则保留元素,已存在则判定为重复直接剔除
            return dedupTagCache.add(itemUniqueTag);
        })
        .collect(Collectors.toList());
    
  • 方案二:按Map内容严格一致标准去重(即key、值完全匹配才算重复)
    先对所有Map做规范化处理,统一key的格式消除原生equals的判断偏差,再调用Stream自带的distinct去重:

    List<Map<String, Object>> dedupList = apptlist.stream()
        .map(originalMap -> {
            // 统一把所有Map的key转小写,消除大小写差异
            Map<String, Object> normalizedMap = new HashMap<>();
            originalMap.forEach((key, value) -> normalizedMap.put(key.toLowerCase(), value));
            return normalizedMap;
        })
        // 规范化后Map的equals判断符合预期,distinct即可正常生效
        .distinct()
        .collect(Collectors.toList());
    
实现注意事项
  • 如果Map中存储的是自定义复杂对象,需要根据实际业务调整唯一标识的生成规则,避免直接调用对象toString()导致同内容对象生成不同标识的问题。
  • 若使用并行流做处理,缓存容器必须使用线程安全的实现,不要直接用普通HashSet/HashMap,否则会出现并发安全问题。

内容的提问来源于stack exchange,提问作者sandy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.08 04:24:04