迭代器模式是行為型設計模式的經典應用,**將遍歷邏輯從集合容器中分離**,提供統一的訪問介面,使算法與數據結構解耦。Java 集合框架通過 Iterable (可迭代) 和 Iterator (迭代器) 兩大介面實現此模式,並賦予 for-each 循環 語法糖支持。
public interface Iterable {
// 核心方法:返回一個新的迭代器實例
Iterator iterator();
// 默認方法 (JDK 8):forEach 消費式遍歷
default void forEach(Consumer super T> action) {
Objects.requireNonNull(action);
for (T t : this) action.accept(t);
}
// 默認方法 (JDK 8):Spliterator 並行流支持
default Spliterator spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
語義: 實現此介面的類 (如 List, Set, Collection) 表示「我可以被遍歷」,每次調用 iterator() 應返回**獨立的新迭代器實例**,互不干擾。
public interface Iterator {
// 是否有下一個元素
boolean hasNext();
// 返回下一個元素並移動游標
E next();
// 從底層集合移除上次 next() 返回的元素 (可選操作)
default void remove() {
throw new UnsupportedOperationException("remove");
}
// 默認方法 (JDK 8):forEachRemaining 批量消費
default void forEachRemaining(Consumer super E> action) {
Objects.requireNonNull(action);
while (hasNext()) action.accept(next());
}
}
核心協議:
hasNext() 不移動游標,可重複調用。next() 必須在 hasNext() == true 時調用,否則拋 NoSuchElementException。remove() 僅能在 next() 後調用一次,調用前後不可再調用 next() (否則 IllegalStateException)。ConcurrentModificationException。// 源碼
for (String s : list) {
System.out.println(s);
}
// 編譯後等價字節碼 (簡化)
Iterator it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
要求: 表達式必須是 Iterable 實現類或**數組** (數組由編譯器特殊處理,不實現 Iterable)。
public class LinkedList implements Iterable {
private Node head;
private int size;
private static class Node {
E item;
Node next;
Node(E item, Node next) { this.item = item; this.next = next; }
}
// 實現 Iterable 契約:返回獨立迭代器
@Override
public Iterator iterator() {
return new LinkedListIterator();
}
// 內部類實現 Iterator,封裝遍歷狀態
private class LinkedListIterator implements Iterator {
private Node current = head;
private Node lastReturned = null; // 支持 remove()
@Override
public boolean hasNext() {
return current != null;
}
@Override
public E next() {
if (!hasNext()) throw new NoSuchElementException();
lastReturned = current;
current = current.next;
return lastReturned.item;
}
@Override
public void remove() {
if (lastReturned == null) throw new IllegalStateException();
// 實現移除邏輯 (略)
lastReturned = null; // 防止重複 remove
}
}
// 其他方法: add, get, size...
}
| 特性 | 介面/方法 | 說明 |
|---|---|---|
| 並行流支持 | Iterable.spliterator() | 返回 Spliterator,支持 stream().parallel(),默認基於 Iterator 實現 (非高效),ArrayList 等重寫為高效數組分割器。 |
| 消費式遍歷 | Iterable.forEach() / Iterator.forEachRemaining() | 內部迭代,配合 Lambda 簡潔,JIT 易優化。 |
| 基本類型專用迭代器 | PrimitiveIterator.OfInt/Long/Double | 避免裝箱開銷,IntStream 等流底層使用。 |
| 可移除性檢測 | Iterator.remove() 默認拋異常 | 不可變集合 (如 Collections.unmodifiableList) 迭代器調用 remove 拋 UnsupportedOperationException。 |
// 1. ArrayList: 隨機訪問 O(1) → 索引遍歷最快
for (int i = 0, n = list.size(); i < n; i++) { ... } // 推薦
for (String s : list) { ... } // 略慢 (迭代器對象分配、方法調用開銷)
// 2. LinkedList: 索引訪問 O(n) → 迭代器/for-each 必須
for (String s : list) { ... } // O(n) 總時間
for (int i = 0; i < list.size(); i++) { list.get(i); } // O(n²) 災難!
// 3. HashSet/HashMap: 無索引 → 必須迭代器/for-each
for (String s : set) { ... }
iterator.remove() 安全刪除;新增/修改請收集索引/元素後二次處理,或使用 CopyOnWriteArrayList、ConcurrentHashMap 等並發容器。iterator() 每次返回**新實例**,不可重用舊迭代器遍歷新數據。entrySet() / keySet() / values()** (均實現 Iterable)。Iterable extends E> 只能讀取,Iterator super E> 只能寫入 (PECS 原則)。ORDERED, DISTINCT, SORTED, SIZED, SUBSIZED, IMMUTABLE, CONCURRENT, NONNULL 影響流優化策略。Iterable (容器契約) + Iterator (遍歷狀態封裝) 構成了 Java 統一遍歷抽象的基石。理解其介面契約、語法糖編譯、快速失效機制、JDK 8+ 默認方法增強、基本類型專用迭代器、Spliterator 並行分割原理,能讓你在集合選型、自定義容器開發、流式編程優化、並發安全遍歷等場景中游刃有餘。記住:**for-each 首選可讀性,性能敏感處 ArrayList 用索引,LinkedList/Set/Map 必用迭代器**。