您好,登錄后才能下訂單哦!
這篇文章主要介紹在foreach循環(huán)中JAVA集合不能添加或刪除元素的原因是什么,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
在《阿里巴巴Java開發(fā)手冊(cè)》中,針對(duì)集合操作,有一項(xiàng)規(guī)定,如下:
【強(qiáng)制】不要在 foreach 循環(huán)里進(jìn)行元素的 remove/add 操作。remove 元素請(qǐng)使用 Iterator方式,如果并發(fā)操作,需要對(duì) Iterator 對(duì)象加鎖。
public class SimpleTest { public static void main(String[] args) { List<String> list = Lists.newArrayList(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); //正例 Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if ("1".equalsIgnoreCase(item)) { iterator.remove(); } } //反例 for (String item : list) { if ("2".equals(item)) { list.remove(item); } } } }
在循環(huán)或迭代時(shí),會(huì)首先創(chuàng)建一個(gè)迭代實(shí)例,這個(gè)迭代實(shí)例的expectedModCount 賦值為集合的modCount.
每當(dāng)?shù)魇? hashNext() / next() 遍歷下?個(gè)元素之前,都會(huì)檢測(cè) modCount 變量與expectedModCount 值是否相等,相等的話就返回遍歷;否則就拋出異常【ConcurrentModificationException】,終?遍歷
如果在循環(huán)中添加或刪除元素,是直接調(diào)用集合的add,remove方法【導(dǎo)致了modCount增加或減少】,但這些方法不會(huì)修改迭代實(shí)例中的expectedModCount,導(dǎo)致在迭代實(shí)例中expectedModCount 與 modCount的值不相等,拋出ConcurrentModificationException異常
但迭代器中的remove,add方法,會(huì)在調(diào)用集合的remove,add方法后,將expectedModCount 重新賦值為modCount,所以在迭代器中增加、刪除元素是可以正常運(yùn)行的。
可以參考ArrayList中的內(nèi)部私有類Itr、ListItr的源碼
public Iterator<E> iterator() { return new Itr(); } /** * An optimized version of AbstractList.Itr */ private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount; Itr() {} //刪除了一些代碼 public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
快速失敗(fail-fast) 是 Java 集合的?種錯(cuò)誤檢測(cè)機(jī)制。在使?迭代器對(duì)集合進(jìn)?遍歷的時(shí)候,在多線程下操作?安全失敗(fail-safe)的集合類可能就會(huì)觸發(fā) fail-fast 機(jī)制,導(dǎo)致拋出ConcurrentModificationException 異常。
另外,在單線程下,如果在遍歷過程中對(duì)集合對(duì)象的內(nèi)容進(jìn)?了修改的話也會(huì)觸發(fā) fail-fast 機(jī)制。
舉個(gè)例?:多線程下,如果線程 1 正在對(duì)集合進(jìn)?遍歷,此時(shí)線程 2 對(duì)集合進(jìn)?修改(增加、刪除、修改),或者線程 1 在遍歷過程中對(duì)集合進(jìn)?修改,都會(huì)導(dǎo)致線程 1 拋出ConcurrentModificationException 異常。
采?安全失敗機(jī)制的集合容器,在遍歷時(shí)不是直接在集合內(nèi)容上訪問的,?是先復(fù)制原有集合內(nèi)容,在拷?的集合上進(jìn)?遍歷。所以,在遍歷過程中對(duì)原集合所作的修改并不能被迭代器檢測(cè)到,故不會(huì)拋ConcurrentModificationException 異常。
以上是“在foreach循環(huán)中JAVA集合不能添加或刪除元素的原因是什么”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。