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

Java ArrayList 遍歷刪除陷阱:為什麼刪除了錯誤元素?正確姿勢詳解

     編輯:程式設計綜合問答

問題重現

List<ForTest> list = new ArrayList<>();
list.add(new ForTest("1")); // index 0
list.add(new ForTest("2")); // 1
list.add(new ForTest("3")); // 2
list.add(new ForTest("4")); // 3
list.add(new ForTest("5")); // 4
// ... 共 7 個元素

for (int i = 0; i < list.size(); i++) {
    ForTest test = list.get(i);
    if (test.getFlag().equals("3")) {
        list.remove(i); // 刪除 index 2 ("3")
    }
    System.out.println("循環到:" + i + ", flag=" + test.getFlag());
}

輸出:

循環到:0, flag=1
循環到:1, flag=2
循環到:2, flag=3  <-- 刪除 "3"
循環到:3, flag=5  <-- 本意應為 "4",實際打印 "5"!
循環到:4, flag=6
循環到:5, flag=7

結果:元素 "4" 被跳過,"5" 移到了 index 3 被打印。

根因分析:索引位移

  • 刪除 index 2 後,原 index 3 ("4")、4 ("5")… 依次前移一位。
  • 循環下一輪 `i` 變為 3,此時 `list.get(3)` 取到的是原 index 4 的 "5"。
  • 導致 "4" 永遠不會被檢查,若 "4" 也符合刪除條件則會漏刪。

三種正確解法

1. 逆序遍歷(最簡單、無需額外集合)

for (int i = list.size() - 1; i >= 0; i--) {
    if (list.get(i).getFlag().equals("3")) {
        list.remove(i); // 刪除後,較小索引元素不受影響
    }
}

2. Iterator 迭代器刪除(標準模式)

Iterator<ForTest> it = list.iterator();
while (it.hasNext()) {
    ForTest test = it.next();
    if (test.getFlag().equals("3")) {
        it.remove(); // 安全刪除,不拋 ConcurrentModificationException
    }
}

3. Java 8+ Stream 過濾收集新列表(函數式風格)

list = list.stream()
           .filter(t -> !t.getFlag().equals("3"))
           .collect(Collectors.toList());

注意:此法生成新列表,原列表引用改變,若有其他引用持有舊列表需謹慎。

性能對比

方法時間複雜度空間適用場景
逆序 forO(n)O(1)ArrayList、LinkedList 通用,就地修改
IteratorO(n)O(1)所有 List 實現,標準 API
Stream filterO(n)O(n)需保留原列表、鏈式操作、並行流

避坑清單

  • ❌ 正序 for + `remove(i)` → 索引位移導致漏檢/越界
  • ❌ for-each 循環中 `list.remove()` → 拋 ConcurrentModificationException
  • ✅ 逆序 for / Iterator / Stream filter / `removeIf(predicate)` (Java 8+)

一行代碼最優解(Java 8+)

list.removeIf(t -> t.getFlag().equals("3"));

內部實現即為 Iterator 遍歷刪除,簡潔高效,推薦作為首選。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved