问题原因remove倒数第二个后,ArrayList集合私有属性size=size -1。
接着迭代下一次循环时先判断 hasNext,
public boolean hasNext() {
return cursor != size;
}
此时游标cursor == size
hasNext返回false 循环结束。会丢失最后一个元素的遍历。
问题的关键点是用的是集合的remove方法,而不是用的是迭代器的remove方法。
正如:用的不是同一厂商的东西,无法保证整体质量效果。
1.迭代器的remove方法
在集合迭代的过程中,为了判断线程的安全,迭代器的方法都会判断集合实际修改的次数与预期的修改次数。
迭代器的remove方法删除元素时会立即修改集合实际修改的次数与预期的修改次数。如下图 红框
附:remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。
2.ArrayList的remove方法
增加List的修改次数。
使用ArrayList的remove方法后,集合还未遍历完,继续下次迭代,调用迭代器的next方法取下一个集合元素。
3.迭代器next方法:
next 中checkForComodification会判断预期元素修改的次数是否等于集合的实际的元素修改次数,由于使用的ArrayList的remove方法。造成modCount != expectedModCoun抛出ConcurrentModificationException异常
写在最后:阿里巴巴java开发手册的一个强制规范:
不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。