首先举ConcurrentModificationException的例子:
public static void main(String[] args) {
List<Integer> list=new ArrayList<Integer>();
list.add(4);
list.add(5);
list.add(3);
list.add(2);
for(Integer i:list){
list.remove(i);
}
}
运行结果:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at qunaer.One.main(One.java:20)
运行的错误提示是ConcurrentModificationException,那么为什么会出现这个错误呢?我们通过ArrayList的源码来看看出现异常的原因。
首先上面的程序作了这些操作:remove。那么我们先看看remove的源码:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
里面有个操作,fastRemove,看源码;
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
首先有个modCount加1。
然后增强for循环遍历集合,底层也是调用的迭代器,集合里有个iterator的方法,返回一个内部类的实例:
public Iterator<E> iterator() {
return new Itr();
}
Itr中有以下内容:
private class Itr implements Iterator<E>
{ int cursor
= 0 ; int lastRet
= - 1 ; int expectedModCount
= modCount; public boolean hasNext()
{ return cursor
!= size(); } public E
next() { 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(); } } |
首先我们看一下它的几个成员变量:
cursor:表示下一个要访问的元素的索引,从next()方法的具体实现就可看出
lastRet:表示上一个访问的元素的索引
expectedModCount:表示对ArrayList修改次数的期望值,它的初始值为modCount。
modCount是AbstractList类中的一个成员变量
里面有个checkForComodification方法,就是判断是否有更改的。当使用list中的remove方法时,并没有更改expectedModCount ,而迭代器中是有更改的,所以如果没有改的话就会报错咯,而且还有一个有意思的地方,你有没有想过如何清空一个集合呢?
看看下面的方法行不行?
public
static void main(String[] args) {
List<Integer> list=new ArrayList<Integer>();
list.add(4);
list.add(5);
list.add(3);
list.add(2);
for(int i=0;i<list.size();i++){
list.remove(i);
}
}
猜对了,不行,大家自己想想为什么,如果不行,是为什么呢?哈哈