如何将扁平化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
相关产品推荐
相关产品推荐

