在foreach循环ArrayList期间remove了其中一个元素,然后就报错了:
Exception in thread "main" java.util.ConcurrentModificationException
用Iterator循环的时候会出现类似的问题。
如果真的要在循环期间remove元素,需要使用for(int i=0;i<list.size();i++)的这种形式。
问题的来源:
问题的来源在于ArrayList的父类AbstractList,是个抽象类,这个类在使用Iterator时使用了一种叫做fail-fast的错误机制,当Iterator在访问ArrayList期间,如果这个ArrayList被改变了,则会抛出ConcurrentModificationException异常。
AbstractList的部分代码是这样的:
package java.util;
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
...
// AbstractList中唯一的属性
// 用来记录List修改的次数:每修改一次(添加/删除等操作),将modCount+1
protected transient int modCount = 0;
// 返回List对应迭代器。实际上,是返回Itr对象。
public Iterator<E> iterator() {
return new Itr();
}
// Itr是Iterator(迭代器)的实现类
private class Itr implements Iterator<E> {
int cursor = 0;
int lastRet = -1;
// 修改数的记录值。
// 每次新建Itr()对象时,都会保存新建该对象时对应的modCount;
// 以后每次遍历List中的元素的时候,都会比较expectedModCount和modCount是否相等;
// 若不相等,则抛出ConcurrentModificationException异常,产生fail-fast事件。
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
// 获取下一个元素之前,都会判断“新建Itr对象时保存的modCount”和“当前的modCount”是否相等;
// 若不相等,则抛出ConcurrentModificationException异常,产生fail-fast事件。
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
...
}
也就是说,每次修改List时,会改变modCount的值,而
Iterator每次调用next()方法时,会判断这个List的modCount和一开始的值是不是一样,如果不一样,就直接抛异常。