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();
}
}