Iterator 模式 將遍歷邏輯從聚合對象中分離,提供統一介面:
Java 集合框架核心介面:
public interface Iterator<E> {
boolean hasNext();
E next();
void remove(); // 可選操作,UnsupportedOperationException
default void forEachRemaining(Consumer<? super E> action) { ... } // Java 8
}
private class Itr implements Iterator<E> {
int cursor; // 下一個待返回元素的索引
int lastRet = -1; // 上一次返回元素的索引,-1 表示無
int expectedModCount = modCount; // 快速失效檢查計數器
public boolean hasNext() {
return cursor != size;
}
public E next() {
checkForComodification();
int i = cursor;
if (i >= size) throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0) throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount; // 同步修改計數
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
cursor:指向下一個將返回元素的索引,初始 0。lastRet:記錄上一次返回元素索引,供 remove() 使用,初始 -1。next() 時:檢查邊界 → 返回 elementData[cursor] → cursor++、lastRet=cursor。modCount:AbstractList 定義的 protected transient int modCount,每次結構性修改(add/remove/clear)自增。expectedModCount:迭代器創建時拍攝的快照值。next()/remove() 前調用 checkForComodification() 比對,不一致拋出 ConcurrentModificationException。lastRet 校驗)。remove(lastRet) → 元素後移 → size-- → modCount++。cursor = lastRet(指向被刪除位置,下次 next 返回原後續元素)、lastRet = -1、expectedModCount = modCount。list.remove() 或 list.add(),會導致 modCount 變化觸發 CME。| 集合 | 底層結構 | 迭代器實現要點 |
|---|---|---|
| LinkedList | 雙向鏈表 | 私有類 ListItr 繼承 AbstractSequentialList.Itr,持有 Node<E> lastReturned, next 引用,next() 移動 next = next.next |
| HashMap | 數組+鏈表/紅黑樹 | HashIterator 持有 Node<K,V> next, current,遍歷桶數組 + 鏈表節點,expectedModCount 同理 |
| TreeMap | 紅黑樹 | PrivateEntryIterator 使用 successor() 中序遍歷獲取下一節點 |
| CopyOnWriteArrayList | 數組(寫時複製) | COWIterator 持有創建時的數組快照 Object[] snapshot,無 modCount、無 CME、弱一致性 |
// 1. 標準 for-each(編譯器自動轉為迭代器)
for (String s : list) { ... }
// 2. 顯式迭代器(需 remove 或 訪問索引)
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
if (shouldRemove(s)) it.remove(); // 唯一安全刪除方式
}
// 3. Java 8+ forEachRemaining
list.forEachRemaining(s -> { ... }); // 內部使用迭代器,不可 remove
// 4. 並發環境:CopyOnWriteArrayList 或 並發包
List safeList = new CopyOnWriteArrayList<>();
for (String s : safeList) { ... } // 遍歷快照,不拋 CME
for (String s : list) if (cond) list.remove(s); → CME。it.remove() 或 list.removeIf(Predicate) (Java 8)。user.setName())安全;增刪元素觸發 CME。Iterator 模式以「游標 + 快照計數器」實現了對動態集合的安全遍歷契約。ArrayList.Itr 作為經典實現,展示了基於數組的索引游標與快速失效檢查的精妙結合。理解其源碼有助於正確使用集合、排查 CME 異常、設計自定義集合類。