为何HashMap在大小未改变时仍抛出ConcurrentModificationException?
为什么HashMap大小没变化,迭代时还是抛出ConcurrentModificationException?
这个问题其实戳中了HashMap fail-fast机制的一个常见误解——它不是单纯检查集合大小有没有变化,而是靠内部的修改计数器来判断的!
先搞懂HashMap的fail-fast核心逻辑
HashMap内部维护了一个叫modCount的变量,它本质是个修改计数器:
- 每次对HashMap做结构性修改(比如
put、remove、clear,甚至包括覆盖已存在key的put操作),这个计数器都会自动加1 - 当你创建迭代器(比如
keySet().iterator()或者entrySet().iterator())时,迭代器会把当前的modCount值存到自己的expectedModCount变量里 - 在迭代过程中,每次调用
next()或者remove()时,迭代器都会检查modCount和expectedModCount是否相等。如果不等,直接抛出ConcurrentModificationException
回到你的场景:大小没变化但计数器变了
你说集合大小没变化却抛异常,大概率是在迭代过程中做了这种操作:调用HashMap的put方法覆盖已存在的key。举个具体的例子,你try块里的代码可能是这样的:
Iterator<String> iterator = myMap.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); // 覆盖已存在的key,集合大小没变,但modCount会加1 myMap.put(key, "updated value"); }
这时候:
- 初始
modCount是4(因为你put了4个元素) - 迭代器创建时
expectedModCount也是4 - 每次执行
put,哪怕key已经存在,HashMap的modCount还是会自增(变成5、6...) - 当下一次调用
iterator.next()时,发现modCount != expectedModCount,就抛出异常了
怎么避免这个问题?
如果需要在迭代时修改集合,必须通过迭代器自身的方法来操作,比如用迭代器的remove()方法:
Iterator<String> iterator = myMap.keySet().iterator(); while (iterator.hasNext()) { String key = iterator.next(); if (key.equals("2")) { // 用迭代器的remove方法,会同步更新expectedModCount iterator.remove(); } }
这种情况下,迭代器在执行remove()时,会把自己的expectedModCount同步为最新的modCount,就不会触发异常了。
总结一下:HashMap的fail-fast机制盯的是修改次数,不是集合大小。只要你在迭代时绕开迭代器直接修改HashMap,哪怕大小没变,也会触发计数器不一致,抛出异常。
内容的提问来源于stack exchange,提问作者user2681668
相关产品推荐
相关产品推荐

