以下内容以ArrayList源码解读
目录
一.问题
集合在遍历删除是可能会报ConcurrentModificationException异常
二.解析
1.要了解这个问题首先要知道引起的原因,是List中的modCount与迭代器中expectedModCount 值不一致导致的
2.了解modCount和expectedModCount
(1.)在AbstractList中定义了 protected transient int modCount = 0; 用这个变量记录该集合被修改的次数,以下这些操作会导致modCount++
- add (用到了ensureCapacityInternal->ensureExplicitCapacity方法进行扩容判断,而此实现modcount++)
- remove
- clear
![](https://i-blog.csdnimg.cn/blog_migrate/ca4cc3b8ce95a32b32c5b5cc3a97ad1a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6284b8aed3f246119089da86db8b168a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/95d77ad8a3f69eaece622e1babb448ac.png)
(2)在调用集合iterator方法时,返回内部类Iterator实例是,迭代器中的expectedModCount会被赋为modCount的值为初始值
![](https://i-blog.csdnimg.cn/blog_migrate/dd38e9d86754905eb8a03dbad5c51f13.png)
在调用迭代器遍历或删除前会校验这两个值是否一致,不一致是抛出ConcurrentModificationException错误
三.结论
1.为什么不能在迭代器中/foreach中直接删除或添加元素
foreach遍历集合,编译后发现就是使用迭代器遍历的(数组则是普通for循环实现)。在迭代器中直接(调用集合的方法)删除或是添加元素,会导致集合中modCount增加,而迭代器中expectedModCount在初次实例时与modCount相等,此时modCount
修改了而expectedModCount未修改,迭代器下次遍历时会调用checkForComodification方法校验modCount和expectedModCount是否相同,不同抛出ConcurrentModificationException错误。
2.如何实现删除
(1)用不同for循环,直接用list的删除方法删除。此时未涉及到迭代器,不存在报错情况;但注意正序删除的下标问题,倒序删除不存在,容易把控(推荐)
(2)用迭代器遍历,用迭代器的删除方法。迭代器的删除方法也是调用了list的删除方法,也会引起modCount++,但是迭代器会有expectedModCount = modCount这一步对齐操作,保证删除成功且不出错(推荐)