在路上壓死只雞,剛想找人商量賠償。
看見一小女孩!我:「孩子!這是你家的雞么?」
孩子:「不是!我家的雞沒有這麼扁。」
ArrayList使用forEach遍歷的時候刪除元素會報錯嗎?
答:其實不一定,如果刪除的元素是倒數第二個則不會報錯,否則報錯ConcurrentModificationException。(答,會報錯,也沒毛病)
原因:舉個例子
List<String> lists = new ArrayList<String>();
lists.add("1");
lists.add("2");
lists.add("3");
lists.add("4");
如果要刪除等於「3」的元素,我們都知道ArrayList底層是類似數組的形式才存儲數據的,生成一個元素後,後面的元素要往前移動,同時lists的size減1。這時lists變成[「1」,「2」,「4」],大小為3。
使用forEach遍歷時:
for(String s :lists){
if(s.equals("3")){
lists.remove(s);
}
}
//這是一顆語法糖,編譯後相當於:
for(Iterator i = lists.iterator();i.hasNext();){
String s = (String)i.next();
if(s.equals("3")){
list.remove(s);
}
}
Iterator的hasNext()方法判斷了size和當前下標cursor是否一樣,一樣則說明已經沒有元素了。
如果remove了「3」這個元素之後,size會變成3,這時候遍歷的下標cursor剛好是3,因此不會再進行下一次循環,直接結束了,此時元素「4」是沒有被遍歷到的。
假如lists中的元素是[「1」,「2」,「3」,「4」,「5」],即3不再是倒數第二個元素了呢?
此時會進行下一次循環,先判斷i.hasNext(),發現當前下標cursor不等於size,執行i.next(),試圖取出下一個值「4」,這時候就報錯了,原因在i.next()中:
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Iterator取下一個值時候會先判斷modCount是否和expectedModCount一樣,不一樣就報錯。
這裡的modCount是刪除的元素的數量計數,expectedModCount是Iterator期望的刪除數量,使用Iterator的remove()方法的時候,Iterator會將調用ArrayList.this.remove(lastRet)刪除元素同時使得modCount++,然後將modCount的值賦給expectedModCount,確保它們一樣。
所以到這裡我們就可以發現問題了,在forEach循環體里,我們直接使用的是lists.remove(「3」)的方法來刪除元素,導致了expectedModCount和modCount不一致。
所以要在遍歷的時候刪除元素,不能使用forEach遍歷的方式,要使用Iterator的方法。
下面是修改後的代碼:
String s= null;
for(Iterator i = lists.iterator(); i.hasNext(); ){
s=(String)i.next();
if(s.equals("3")){
i.remove();
}
}
還有一種方法是使用CopyOnWriteArrayList代替ArrayList,這是一種寫時複製的容器,每次添加刪除元素的時候都會複製一份舊的數據,新建一個新數據,在新數據進行修改後再修改舊數據的指針指到新數據。
這樣的話,遍歷的數據其實都是第一份的舊數據,舊數據是沒有變的,我們使用舊數據遍歷,使用新數據判斷值。
畫個圖表達下我的理解:

來源:blog.csdn.net/awocbb/article/details/85069427
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/229803.html
微信掃一掃
支付寶掃一掃