TreeSet<String> set = new TreeSet<>();
set.add("one1");
set.add("two1");
set.add("three1");
for (Iterator<String> it = set.iterator(); it.hasNext(); ) {
String str = it.next();
System.out.println(str);
if (str.equals("three1")) {
set.remove(str); // 直接操作集合刪除
}
}
執行結果拋出 ConcurrentModificationException,但書上說「遍歷到最後一個元素時操作集合不會拋異常」,為何矛盾?
String 實作 Comparable,比較規則:"one1" < "three1" < "two1"(字典序)。one1 → three1 → two1。Iterator 內部維護 expectedModCount,初始化時等於集合的 modCount。每次 next() 前會檢查:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
當你呼叫 set.remove() 而非 it.remove() 時,modCount 增加,但 expectedModCount 未同步更新,導致下一次 next() 或 hasNext() 觸發異常。
這句話的前提是:刪除的是最後一個元素,且刪除後不再呼叫迭代器的任何方法。
你的案例中,刪除的是中間元素 three1,迭代器還需繼續取 two1,故必拋異常。
if (str.equals("three1")) {
it.remove(); // 安全刪除,會同步 expectedModCount
}
List<String> toRemove = new ArrayList<>();
for (String s : set) {
if (s.equals("three1")) toRemove.add(s);
}
set.removeAll(toRemove);
set.removeIf(s -> s.equals("three1"));
Iterator.remove() 或事後批次處理。CopyOnWriteArraySet 或加鎖。modCount 機制,是 Java 集合框架面試必考點。掌握這些細節,能避開 90% 的集合遍歷坑,寫出更健壯的程式碼。