1. 程式人生 > >for each刪除List中的元素出錯

for each刪除List中的元素出錯

場景是,需要刪除objList中的某幾個元素,自然而然,我們會習慣性的寫下如下語句:
int i = 0;  
for(Object o : objList)  
{  
    if(o == value)  
   {  
       objList.remove(i);   
   }  
   i++;  
}  
報錯:
這時你就會發現報 java.util.ConcurrentModificationException 異常,此異常是迭代器丟擲的異常,官方說明是:
The Iterators returned by this class’s iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator’s own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
大概意思是:在用迭代器迭代集合的時候,迭代器一旦建立,就不允許更改集合,如果所迭代的集合(Set或者List)的有修改的話,就會丟擲 
ConcurrentModificationException異常, 用迭代器自身的remove方法除外…
原理:

用for-each遍歷 實際上使用的是Iterator迭代器 

Iterator的工作機制: 

Iterator是工作在一個獨立的執行緒中,並且擁有一個 mutex鎖,就是說Iterator在工作的時候,是不允許被迭代的物件被改變的。Iterator被建立的時候,建立了一個記憶體索引表(單鏈表),這 個索引表指向原來的物件,當原來的物件數量改變的時候,這個索引表的內容沒有同步改變,所以當索引指標往下移動的時候,便找不到要迭代的物件,於是產生錯 誤。
List、Set等是動態的,可變物件數量的資料結構,但是Iterator則是單向不可變,只能順序讀取,如果逆向讀取,需要重寫iterator(),當 Iterator指向的原始資料發生變化時,Iterator自己就迷失了方向。
解決方法:
刪除指定的元素應該如何呢?
一. 用一個List 記錄要刪除的資料,最後removeAll(List);
List<Integer> removeList = new ArrayList()  
for(Integer i : intList)  
{  
    if(i == 13)  
    {  
        removeList.add(i);  
    }  
}  
//最後  
if(removeList.size()>0)  
{  
    intList.removeAll(removeList);  
}
二.用for迴圈遍歷,原始書寫方式
for(int i = 0; i < intList.size(); i++)  
{  
    if(intList.get(i) == 13)  
    {  
        intList.remove(i);  
        //此時要注意,因為list會動態變化不像陣列會佔位,所以當前索引應該後退一位  
        i--;  
    }  
}
三.用迭代器自帶的remove方法,這也是官方推薦的方法
Iterator <Integer> it = intList.iterator();  
while(it.hasNext())  
{  
    if(it.next() == 13)  
    {  
        it.remove();  
    }  
}