迭代器模式是行為型設計模式之一,提供統一介面順序訪問聚合物件元素,且無需暴露內部結構。Java 集合框架通過 Iterable 介面支援迭代器,本文詳細解析 Iterator 與 ListIterator 的核心方法、使用場景與最佳實踐。
Iterator 僅支援單向移動ConcurrentModificationExceptionjava.util.Iterator<E> 繼承自 Iterable<E>| 方法 | 說明 | 異常 |
|---|---|---|
boolean hasNext() | 判斷是否還有下一個元素 | - |
E next() | 返回下一個元素,游標後移 | NoSuchElementException |
void remove() | 移除最後一次 next() 返回的元素 | IllegalStateException(未調用 next 或重複調用) |
default void forEachRemaining(Consumer<? super E> action) | Java 8+:對剩餘元素執行動作 | - |
ListIterator<E> 繼承 Iterator<E>,專為 List 設計,支援雙向遍歷與元素修改:
| 方法 | 說明 |
|---|---|
boolean hasPrevious() | 是否有前一個元素 |
E previous() | 返回前一個元素,游標前移 |
int nextIndex() | 下一個元素索引 |
int previousIndex() | 前一個元素索引 |
void set(E e) | 替換最後訪問的元素 |
void add(E e) | 在游標位置插入元素 |
List<String> list = new ArrayList<>();
list.add("AA");
list.add("BB");
list.add("CC");
// 風格 1:for 循環(最常用,作用域清晰)
for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
String str = iter.next();
System.out.println(str);
}
// 風格 2:while 循環
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
String str = iter.next();
System.out.println(str);
}
// 風格 3:Java 8+ forEachRemaining
list.iterator().forEachRemaining(System.out::println);
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "B", "D"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
String s = iter.next();
if ("B".equals(s)) {
iter.remove(); // 唯一安全的移除方式
}
}
// 結果:[A, C, D]
List<String> list = new LinkedList<>(Arrays.asList("A", "B", "C"));
ListIterator<String> iter = list.listIterator();
// 正向遍歷並修改
while (iter.hasNext()) {
String s = iter.next();
if ("B".equals(s)) {
iter.set("B_UPDATED"); // 替換
iter.add("INSERTED"); // 在 C 前插入
}
}
// 當前游標在 "C" 後,可反向遍歷
while (iter.hasPrevious()) {
System.out.print(iter.previous() + " "); // 輸出:C INSERTED B_UPDATED A
}
// 編譯通過,運行拋 ConcurrentModificationException
for (String s : list) {
if ("B".equals(s)) list.remove(s); // 禁止!
}
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
if ("B".equals(iter.next())) iter.remove();
}
List<String> filtered = list.stream()
.filter(s -> !"B".equals(s))
.collect(Collectors.toList());
list.removeIf(s -> "B".equals(s)); // 內部使用 Iterator,線程不安全但單線程高效
public class CustomRange implements Iterable<Integer> {
private final int start, end, step;
public CustomRange(int start, int end, int step) {
this.start = start; this.end = end; this.step = step;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int current = start;
@Override
public boolean hasNext() { return current < end; }
@Override
public Integer next() {
if (!hasNext()) throw new NoSuchElementException();
int val = current;
current += step;
return val;
}
};
}
}
// 使用:支援 for-each 循環
for (int i : new CustomRange(0, 10, 2)) {
System.out.println(i); // 0, 2, 4, 6, 8
}
Itr 實現 Iteratorcursor(下一個元素索引)、lastRet(最後返回索引)、expectedModCount(預期修改計數)next() 檢查 modCount == expectedModCount,不一致拋出 ConcurrentModificationExceptionadd/remove/clear 方法remove() 未中間調用 next()| 場景 | 推薦方式 | 時間複雜度 |
|---|---|---|
| 單純遍歷 | for-each / Iterator | O(n) |
| 遍歷中移除 | Iterator.remove() / removeIf() | O(n) |
| 需索引訪問 | for (int i=0; i<size; i++) | O(1) 隨機訪問 |
| 雙向遍歷/插入 | ListIterator | O(1) 插入(LinkedList) |
| 並發環境 | CopyOnWriteArrayList / ConcurrentLinkedQueue | 視實現而定 |
Iterator 是集合遍歷的統一抽象,核心三方法:hasNext()、next()、remove()ListIterator 增加雙向遍歷、索引獲取、元素替換與插入能力remove(),或 Java 8+ removeIf()/StreamIterable 介面即可支援 for-each 循環,擴展性極強熟練掌握迭代器用法,是高效操作 Java 集合、編寫健壯代碼的基礎技能之一。