Java实现Map键对应历史值列表存储时put/get方法异常排查
问题背景
需求是留存Map的全量更新记录:新Map的键和原Map完全一致,每个键对应的值为该键所有历史更新值组成的列表。
原实现思路:
- 从服务端接收Map类型的更新数据
- 定义键对应值列表结构的新Map
- 遍历原Map,将每个键值对追加到新Map对应键的列表中
实际编码时put、get方法运行异常,原错误代码如下:
Map<String, String> map = DatatoJson.main(null); Map<String, Map<String, List<String>>> new_map = new HashMap<String, Map<String, List<String>>>(); for (Map.Entry<String, String> entry : map.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); // check if a new map called new_map is empty in Java if (new_map.isEmpty()) { // include key and value of map in the new map "new_map" new_map.put(key, value); } // check if the key of the map is already in the new map if (new_map.containsKey(key)) { // get the key of new_map Map<String, List<String>> new_key = new_map.get(key); // check if new_key and key are the same if (new_key.equals(key)) { // if they are the same, then add the value of map to a value list in new_map corresponding to the key new_map.get(key).add(value); } } }
错误原因
- 泛型定义冗余错误:需求只需要「键->值列表」的一层映射,不需要额外嵌套一层Map,定义的
Map<String, Map<String, List<String>>>类型要求value必须是Map结构,但代码尝试往里面存String类型值,直接触发类型不匹配错误,这是put方法失效的核心原因。 - 初始化逻辑无意义:判断
new_map整体为空才插入第一个值的逻辑完全多余,多批次更新时只要Map里有一个键,后续新键的第一次插入就会被跳过。 - 类型比较逻辑无效:从
new_map取出的value是Map类型,和String类型的key做equals判断永远返回false,后续追加值的逻辑根本不会执行。 - 空指针风险:就算key匹配逻辑正常,代码也没有为首次出现的key初始化对应的List容器,直接调用
add方法会抛出空指针异常。
修正后实现
// 新Map只需要定义为 键->对应历史值列表 的结构即可,不需要嵌套Map Map<String, List<String>> historyMap = new HashMap<>(); // 每次从服务端拿到更新数据后,重复执行下面的遍历逻辑即可追加历史记录 Map<String, String> updateMap = DatatoJson.main(null); for (Map.Entry<String, String> entry : updateMap.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); // 如果当前key是第一次出现,先初始化对应的空列表 if (!historyMap.containsKey(key)) { historyMap.put(key, new ArrayList<>()); } // 把当前值追加到对应key的历史列表里 historyMap.get(key).add(value); }
Java 8及以上版本可以用
computeIfAbsent简化写法,无需手动判断key是否存在:for (Map.Entry<String, String> entry : updateMap.entrySet()) { historyMap.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).add(entry.getValue()); }
内容的提问来源于stack exchange,提问作者christheliz
相关产品推荐
相关产品推荐

