在沒有統一遍歷介面之前,陣列用 for (int i=0; i<size; i++),鏈表用 while ((e=e.next())!=null)。客戶端代碼與具體集合內部結構強耦合,一旦將 ArrayList 換成 LinkedList,遍歷邏輯就得全改寫。Iterator 模式正是為了解決這個問題而生:以統一介面隱藏內部結構,實現遍歷邏輯與集合實現的解耦。
boolean add(E e):回傳值非表示成功與否,而是「集合內容是否發生變化」;失敗必須拋出異常。iterator():工廠方法,回傳專屬的 Iterator 實例,啟動統一遍歷流程。public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
標準遍歷慣用語:
for (Iterator it = c.iterator(); it.hasNext(); ) {
Object o = it.next();
// 處理 o
}
JDK 1.5 引入增強 for 循環 for (Type t : c),編譯器自動轉換為上述 Iterator 代碼。
AbstractList 以 private class Itr implements Iterator 實現迭代器,iterator() 僅回傳 new Itr()。客戶端完全不知具體類型,完美體現「面向介面編程」。
int cursor = 0:下一次 next() 將回傳的元素索引。int lastRet = -1:上一次回傳元素的索引,供 remove() 使用。int expectedModCount = modCount:快照式記錄集合修改次數,用於檢測並發修改。public boolean hasNext() {
return cursor != size();
}
public Object next() {
checkForComodification();
try {
Object next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
僅允許透過 Iterator 自身的 remove() 刪除當前元素,內部會同步更新 expectedModCount = modCount,避免拋出 ConcurrentModificationException。此異常屬 RuntimeException,絕不可捕捉忽略,出現即表示程式邏輯有誤,需修正代碼而非吞掉異常。
CopyOnWriteArrayList 等並發安全容器。Collection c = new ArrayList();
c.add("abc");
c.add("xyz");
for (Iterator it = c.iterator(); it.hasNext(); ) {
String s = (String) it.next();
System.out.println(s);
}
將第一行換成 new LinkedList() 或 new Vector(),其餘代碼完全不用動,功能不變——這就是「依賴抽象不依賴具體」的威力。