首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java List 遍歷刪除元素完全指南:為什麼只有 Iterator 安全?

     編輯:Java 綜合教學

三種遍歷方式對比

方式適用場景刪除元素後果
增強 for(for-each)唯讀遍歷拋出 ConcurrentModificationException
普通 for (index)需索引操作索引錯位導致漏刪或越界
Iterator 迭代器需邊遍歷邊刪除唯一安全方式,呼叫 iterator.remove()

錯誤示範與根因分析

1. 增強 for 刪除 → ConcurrentModificationException

List<Student> list = new ArrayList<>();
String[] names = {"aaa","bbb","ccc"};
for (Student stu : list) {
    for (String name : names) {
        if (stu.getName().equals(name)) {
            list.remove(stu); // 第一次刪除後,迭代器內部 modCount 改變,下一次 hasNext() 檢測失敗拋出異常
        }
    }
}

根因:增強 for 底層使用 Iterator,迭代器建立時記錄 expectedModCount = modCount。集合結構變更(remove/add)會修改 modCount,導致 expectedModCount != modCount,觸發快速失效機制。

2. 普通 for 刪除 → 索引錯位漏刪

for (int i = 0; i < list.size(); i++) {
    if (list.get(i).getName().equals("target")) {
        list.remove(i); // 刪除後後續元素前移,原 i+1 位置元素變為新 i 位置,循環 i++ 導致跳過該元素
    }
}

修正:倒序遍歷 for (int i = list.size()-1; i >= 0; i--) 或刪除後 i--。

正確姿勢:Iterator.remove()

Iterator<Student> it = list.iterator();
while (it.hasNext()) {
    Student stu = it.next();
    if (namesContains(stu.getName())) {
        it.remove(); // 迭代器內部同步更新 expectedModCount,結構變更合法
    }
}

Iterator.remove() 是唯一被 ArrayList、LinkedList 等標準集合支援的安全刪除方法,內部會同步修改 expectedModCount 避免快速失效。

Java 8+ 函數式替代方案

// 過濾保留不符合條件的元素(建立新列表,原列表不變)
List<Student> filtered = list.stream()
    .filter(stu -> !namesContains(stu.getName()))
    .collect(Collectors.toList());

// 原地刪除(需可變列表)
list.removeIf(stu -> namesContains(stu.getName()));

removeIf 內部同樣使用迭代器遍歷並呼叫 iterator.remove(),線程不安全場景下等價於手寫 Iterator 迴圈,但語意更清晰。

總結建議

  1. 唯讀遍歷:優先 for-each 或 stream()。
  2. 需刪除:Java 8+ 用 removeIf;舊版本用 Iterator 手寫迴圈。
  3. 需索引配合刪除:倒序 for (int i = size-1; i >= 0; i--)。
  4. 多線程環境:使用 CopyOnWriteArrayList 或加鎖同步。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved