You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将扁平化HashMap反嵌套为多层结构?遇并发修改异常求解决

问题分析与解决方案

咱们先拆解你遇到的核心问题:你的代码目前有三个关键缺陷导致功能失效和ConcurrentModificationException,同时完全没覆盖需求中的数组嵌套场景。

现有代码的核心问题

1. 子键查找逻辑完全错误

在doUnflatten方法里,你错误地从原扁平化Map(flattened)中获取子键的值:

Object current = flattened.get(part);

这明显不对——原Map里只有a.b.c这类完整键,根本不存在a、b这种拆分后的子键,这直接导致嵌套结构的构建逻辑混乱,甚至会出现莫名其妙的对象覆盖。

2. 完全未处理数组嵌套场景

你的需求明确要求把g: [ g.h: nested_value1, g.i: nested_value2 ]转成g: [ {h: nested_value1}, {i: nested_value2} ],但现有代码完全没考虑数组/集合类型的处理逻辑,这部分需求直接无法实现。

3. 并发修改异常的潜在触发点

虽然你遍历的是flattened.keySet(),但如果在doUnflatten过程中误操作修改了原Map,或者调用方法时其他线程同时修改原Map,就会触发ConcurrentModificationException。不过结合你的代码逻辑,更可能是前面的逻辑错误间接引发了异常。

修正后的实现方案

下面是重构后的代码,既解决了嵌套Map的反扁平化,也支持了你需求中的数组场景,同时从根源上避免了并发修改异常:

import org.apache.commons.lang3.StringUtils;
import java.util.*;

public class MapUnflattener {

    public static Map<String, Object> unflatten(Map<String, Object> flattened) {
        // 用LinkedHashMap保证遍历顺序(可选,按需调整)
        Map<String, Object> unflattened = new LinkedHashMap<>();
        
        // 遍历entrySet而非keySet,避免潜在的并发问题
        for (Map.Entry<String, Object> entry : flattened.entrySet()) {
            String fullKey = entry.getKey();
            Object value = entry.getValue();
            
            // 处理值为嵌套Map的数组场景
            if (value instanceof Map) {
                List<Object> nestedList = new ArrayList<>();
                Map<String, Object> nestedMap = (Map<String, Object>) value;
                for (Map.Entry<String, Object> nestedEntry : nestedMap.entrySet()) {
                    // 提取嵌套键的最后一级,比如g.h -> h
                    String[] nestedParts = StringUtils.split(nestedEntry.getKey(), '.');
                    String subKey = nestedParts[nestedParts.length - 1];
                    Map<String, Object> itemMap = new HashMap<>();
                    itemMap.put(subKey, nestedEntry.getValue());
                    nestedList.add(itemMap);
                }
                // 把构建好的数组放到对应层级
                buildNestedMap(unflattened, fullKey, nestedList);
            } else {
                // 普通嵌套Map的处理逻辑
                buildNestedMap(unflattened, fullKey, value);
            }
        }
        return unflattened;
    }

    private static void buildNestedMap(Map<String, Object> targetMap, String fullKey, Object value) {
        String[] keyParts = StringUtils.split(fullKey, '.');
        Map<String, Object> currentMap = targetMap;
        
        for (int i = 0; i < keyParts.length; i++) {
            String part = keyParts[i];
            if (i == keyParts.length - 1) {
                // 最后一级键,直接赋值
                currentMap.put(part, value);
            } else {
                // 安全创建或获取嵌套层级的Map,避免空指针
                currentMap = (Map<String, Object>) currentMap.computeIfAbsent(part, k -> new HashMap<>());
            }
        }
    }
}

关键改进点说明

  • 修正子键查找逻辑:用computeIfAbsent安全地创建或获取嵌套层级的Map,完全基于目标Map构建结构,不再依赖原扁平化Map的错误查找。
  • 支持数组嵌套场景:判断值是否为Map类型(对应需求中的数组结构),提取嵌套键的最后一级构建数组元素,完美匹配你要的转换效果。
  • 避免并发修改异常:遍历entrySet而非keySet,且全程不修改原扁平化Map,从根源上杜绝了该异常。
  • 简化逻辑结构:把嵌套Map的构建逻辑抽离到单独方法,代码更清晰、易维护。

测试示例

假设你有如下扁平化Map:

Map<String, Object> flattened = new HashMap<>();
flattened.put("a.b.c", "value1");
flattened.put("e.f", "value2");

Map<String, Object> gNested = new HashMap<>();
gNested.put("g.h", "nested_value1");
gNested.put("g.i", "nested_value2");
flattened.put("g", gNested);

调用unflatten(flattened)后,得到的结果就是你需要的嵌套结构:

{
  "a": {"b": {"c": "value1"}},
  "e": {"f": "value2"},
  "g": [{"h": "nested_value1"}, {"i": "nested_value2"}]
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:52:28