为何这段ArrayList遍历删除代码会引发ConcurrentModificationError?
首先得明确:你写的for (int e : l3)这种foreach循环,底层是靠**迭代器(Iterator)**实现的。ArrayList的迭代器有个核心校验机制,用来防止遍历过程中列表被“意外修改”,这就是你遇到错误的根源。
迭代器的核心校验逻辑
ArrayList内部维护了一个modCount变量,专门记录列表被修改(添加、删除元素)的总次数。当你创建迭代器时,它会把当前的modCount值复制到自己的expectedModCount变量里。
之后每次迭代器调用next()方法取下一个元素时,都会先做一件事:检查modCount和expectedModCount是否相等。如果不相等,就直接抛出ConcurrentModificationError——这就是所谓的“迭代器被干扰”,因为迭代器认为自己遍历的列表应该是“一成不变”的,一旦外部修改了列表,它就判定遍历环境被破坏了。
结合你的代码分析错误触发过程
看你的代码,初始列表是[0,2,3,5],modCount初始值是4(因为执行了4次add操作)。当foreach循环启动时,迭代器初始化,expectedModCount也被设为4。
接下来的执行步骤:
- 第一次循环:取出元素
0,判断是偶数,调用l3.remove(i)(此时i=0)删除第一个元素。这时候ArrayList的modCount会自动加1,变成5,但迭代器的expectedModCount还是4。 - 迭代器准备取下一个元素,调用
next()方法时,发现modCount != expectedModCount,直接抛出ConcurrentModificationError。
另外提一句:你的i++逻辑本身也有问题——就算没触发错误,删除元素后列表长度缩短,索引会错位,导致后续元素要么被重复处理,要么被跳过,但这是次要问题,核心错误还是迭代器的校验机制被触发了。
正确的做法:用迭代器自身的remove方法
如果要在遍历过程中删除元素,应该用迭代器自带的remove()方法,它会同步更新expectedModCount和modCount,避免校验失败:
List<Integer> l3 = new ArrayList<>(); l3.add(0); l3.add(2); l3.add(3); l3.add(5); Iterator<Integer> iter = l3.iterator(); while (iter.hasNext()) { int e = iter.next(); if (e % 2 == 0) { iter.remove(); } }
这样迭代器每次删除元素时,都会把自己的expectedModCount更新成当前的modCount,下次调用next()时校验就会通过。
内容的提问来源于stack exchange,提问作者Nadeem Hussain

