網(wǎng)上的解釋原因:
Iterator 是工作在一個(gè)獨(dú)立的線程中,并且擁有一個(gè) 互斥 鎖。 Iterator 被創(chuàng)建之后會(huì)建立一個(gè)指向原來(lái)對(duì)象的單鏈索引表,當(dāng)原來(lái)的對(duì)象數(shù)量發(fā)生變化時(shí),這個(gè)索引表的內(nèi)容不會(huì)同步改變,所以當(dāng)索引指針往后移動(dòng)的時(shí)候就找不到要迭代的對(duì)象,所以按照 fail-fast 原則 Iterator 會(huì)馬上拋出 java.util.ConcurrentModificationException 異常。
所以 Iterator 在工作的時(shí)候是不允許被迭代的對(duì)象被改變的。但你可以使用 Iterator 本身的方法 remove() 來(lái)刪除對(duì)象, Iterator.remove() 方法會(huì)在刪除當(dāng)前迭代對(duì)象的同時(shí)維護(hù)索引的一致性。
廖雪峰 大師 Java源碼分析:深入探討Iterator模式
http://gceclub.sun.com.cn/yuanchuang/week-14/iterator.html
在工作碰到這個(gè)問(wèn)題所有看看:
List list = ...;
for(Iterator iter = list.iterator(); iter.hasNext();) {
Object obj = iter.next();
...
if(***) {
list.remove(obj); //list.add(obj) 其實(shí)也是一樣的。
}
}
在執(zhí)行了remove方法之后,再去執(zhí)行循環(huán),iter.next()的時(shí)候,報(bào)java.util.ConcurrentModificationException(當(dāng)然,如果remove的是最后一條,就不會(huì)再去執(zhí)行next()操作了),
下面來(lái)看一下源碼
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
public interface Collection<E> extends Iterable<E> {
...
Iterator<E> iterator();
boolean add(E o);
boolean remove(Object o);
...
}
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//AbstractCollection和List都繼承了Collection
protected transient int modCount = 0;
private class Itr implements Iterator<E> { //內(nèi)部類(lèi)Itr
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification(); //該方法中檢測(cè)到改變,從而拋出異常
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); //執(zhí)行remove對(duì)象的操作
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount; //重新設(shè)置了expectedModCount的值,避免了ConcurrentModificationException的產(chǎn)生
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount) //當(dāng)expectedModCount和modCount不相等時(shí),就拋出ConcurrentModificationException
throw new ConcurrentModificationException();
}
}
}
remove(Object o)在ArrayList中實(shí)現(xiàn)如下:
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;
}
private void fastRemove(int index) {
modCount++; //只增加了modCount
....
}
所以,產(chǎn)生ConcurrentModificationException的原因就是:
執(zhí)行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后當(dāng)代碼執(zhí)行到next()方法時(shí),判斷了checkForComodification(),發(fā)現(xiàn)兩個(gè)數(shù)值不等,就拋出了該Exception。
要避免這個(gè)Exception,就應(yīng)該使用remove()方法,但是沒(méi)有add()方法了,只能另建一個(gè)list來(lái)處理這個(gè)問(wèn)題了。