List遍歷時刪除元素的正確方式舉例

當要刪除ArrayList里面的某個元素,一不注意就容易出bug。今天就給大家說一下在ArrayList循環(huán)遍歷并刪除元素的問題。首先請看下面的例子:

import java.util.ArrayList;

public class ArrayListRemove

{

public static void main(String[] args)

{

ArrayList list = new ArrayList();

list.add("a");

list.add("b");

list.add("b");

list.add("c");

list.add("c");

remove(list);

for (String s : list)

{

System.out.println("element : " + s);

}

}

public static void remove(ArrayList list)

{

}

}

常見錯誤寫法:

舉例一:

Java

結果:第二個“b”的字符串沒有刪掉。

舉例二:

Java

結果:這種for-each寫法會報出并發(fā)修改異常:java.util.ConcurrentModificationException。

錯誤原因:先看下ArrayList中的remove方法,看入?yún)镺bject的remove方法是怎么實現(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;

}

執(zhí)行路徑會到else路徑下最終調用faseRemove方法:

private void fastRemove(int index) {

modCount++;

int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index,numMoved);

elementData[--size] = null; // Let gc do its work

}

可以看到會執(zhí)行System.arraycopy方法,導致刪除元素時涉及到數(shù)組元素的移動。針對錯誤寫法一,在遍歷第一個字符串b時因為符合刪除條件,所以將該元素從數(shù)組中刪除,并且將后一個元素移動(也就是第二個字符串b)至當前位置,導致下一次循環(huán)遍歷時后一個字符串b并沒有遍歷到,所以無法刪除。針對這種情況可以倒序刪除的方式來避免:

Java

因為數(shù)組倒序遍歷時即使發(fā)生元素刪除也不影響后序元素遍歷。

實例二的錯誤原因。產(chǎn)生的原因卻是foreach寫法是對實際的Iterable、hasNext、next方法的簡寫,問題同樣處在上文的fastRemove方法中,可以看到第一行把modCount變量的值加一,但在ArrayList返回的迭代器:

public Iterator iterator() { return new Itr();}

這里返回的是AbstractList類內(nèi)部的迭代器實現(xiàn)private class Itr implements Iterator,看這個類的next方法:

Java

第一行checkForComodification方法:

final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException();}

這里會做迭代器內(nèi)部修改次數(shù)檢查,因為上面的remove(Object)方法修改了modCount的值,所以才會報出并發(fā)修改異常。要避免這種情況的出現(xiàn)則在使用迭代器迭代時(顯示或for-each的隱式)不要使用ArrayList的remove,改為用Iterator的remove即可。

public static void remove(ArrayList list)

{

Iterator it = list.iterator();

while (it.hasNext())

{

String s = it.next();

if (s.equals("b"))

{

it.remove();

}

}

}

歡迎加入我的Java交流群:657741243。點擊鏈接加入群聊【java高級開發(fā)交流】:https://jq.qq.com/?_wv=1027&k=5bEMa9n

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容