使用两个迭代器遍历单个Map触发ConcurrentModificationException问题
为什么使用两个迭代器操作Map会触发ConcurrentModificationException?
核心原因
Java里像TreeMap这类集合的迭代器是**快速失败(fail-fast)**机制:每个迭代器创建时会记录当前集合的修改次数(modCount),之后每次调用next()都会检查集合实际修改次数和迭代器记录的是否一致,一旦不一致就抛出ConcurrentModificationException,避免迭代器处理过期数据。
你的代码问题出在两个迭代器共享同一个entrySet:
- 你从同一个
detailEntrySet(对应lMap的entrySet)创建了iterator和iterator1两个迭代器 - 第一个迭代器
iterator执行remove()时,会修改Map的结构,同时更新Map的modCount值,但第二个迭代器iterator1记录的expectedModCount还是创建时的旧值 - 当你启动第二个while循环调用
iterator1.next()时,迭代器检测到modCount和expectedModCount不匹配,立刻抛出异常
哪怕你用的是迭代器自身的remove()方法修改结构,只要是其他迭代器,依然会触发这个检测——每个迭代器只认自己创建时的修改次数。
修复方案
有两种简单的修复方式:
方案1:操作完第一个迭代器后,重新创建第二个迭代器
public static void main(String[] args) { for (int i = 0; i <= 3; i++) { Map<Integer, List<String>> lMap = new TreeMap<>(); lMap.put(95, Arrays.asList("Hello", "World!", "How", "Are", "You")); lMap.put(13, Arrays.asList("Adhar", "kumar", "patra")); lMap.put(76, Arrays.asList("sivam", "Panday")); Set<Entry<Integer, List<String>>> detailEntrySet = lMap.entrySet(); Iterator<Entry<Integer, List<String>>> iterator = detailEntrySet.iterator(); System.out.println("******************:=" + i); // 第一个遍历删除 while (iterator.hasNext()) { List<String> value = iterator.next().getValue(); if(value.stream().anyMatch(a->a.contains("Are"))) { iterator.remove(); } } // 重新创建迭代器,此时会读取最新的modCount Iterator<Entry<Integer, List<String>>> iterator1 = detailEntrySet.iterator(); while (iterator1.hasNext()) { List<String> value = iterator1.next().getValue(); if(value.stream().anyMatch(a->a.contains("patra"))) { iterator1.remove(); } } } }
方案2:用同一个迭代器完成所有删除逻辑(更高效)
public static void main(String[] args) { for (int i = 0; i <= 3; i++) { Map<Integer, List<String>> lMap = new TreeMap<>(); lMap.put(95, Arrays.asList("Hello", "World!", "How", "Are", "You")); lMap.put(13, Arrays.asList("Adhar", "kumar", "patra")); lMap.put(76, Arrays.asList("sivam", "Panday")); Set<Entry<Integer, List<String>>> detailEntrySet = lMap.entrySet(); Iterator<Entry<Integer, List<String>>> iterator = detailEntrySet.iterator(); System.out.println("******************:=" + i); // 一次遍历判断所有删除条件 while (iterator.hasNext()) { List<String> value = iterator.next().getValue(); if(value.stream().anyMatch(a->a.contains("Are")) || value.stream().anyMatch(a->a.contains("patra"))) { iterator.remove(); } } } }
内容的提问来源于stack exchange,提问作者Patra Adhar
相关产品推荐
相关产品推荐

