首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 迭代器模式深度解析:Iterator 與 Iterable 雙介面協作機制

     編輯:Java 綜合教學

Java 迭代器模式深度解析:Iterator 與 Iterable 雙介面協作機制

迭代器模式是行為型設計模式的經典應用,**將遍歷邏輯從集合容器中分離**,提供統一的訪問介面,使算法與數據結構解耦。Java 集合框架通過 Iterable (可迭代) 和 Iterator (迭代器) 兩大介面實現此模式,並賦予 for-each 循環 語法糖支持。

一、 核心介面定義與契約 (JDK 8+)

1. Iterable<T> — 可迭代對象 (被遍歷者)

public interface Iterable {
    // 核心方法:返回一個新的迭代器實例
    Iterator iterator();
    
    // 默認方法 (JDK 8):forEach 消費式遍歷
    default void forEach(Consumer 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() 應返回**獨立的新迭代器實例**,互不干擾。

2. Iterator<E> — 迭代器 (遍歷者)

public interface Iterator {
    // 是否有下一個元素
    boolean hasNext();
    
    // 返回下一個元素並移動游標
    E next();
    
    // 從底層集合移除上次 next() 返回的元素 (可選操作)
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    
    // 默認方法 (JDK 8):forEachRemaining 批量消費
    default void forEachRemaining(Consumer action) {
        Objects.requireNonNull(action);
        while (hasNext()) action.accept(next());
    }
}

核心協議:

  • hasNext() 不移動游標,可重複調用。
  • next() 必須在 hasNext() == true 時調用,否則拋 NoSuchElementException。
  • remove() 僅能在 next() 後調用一次,調用前後不可再調用 next() (否則 IllegalStateException)。
  • 快速失效: 遍歷過程中集合結構性修改 (非通過 iterator.remove()) 會拋 ConcurrentModificationException。

二、 for-each 語法糖編譯原理

// 源碼
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)。

三、 實戰:自定義集合實現 Iterable 與 Iterator

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...
}

四、 進階特性與 JDK 8+ 增強

特性介面/方法說明
並行流支持Iterable.spliterator()返回 Spliterator,支持 stream().parallel(),默認基於 Iterator 實現 (非高效),ArrayList 等重寫為高效數組分割器。
消費式遍歷Iterable.forEach() / Iterator.forEachRemaining()內部迭代,配合 Lambda 簡潔,JIT 易優化。
基本類型專用迭代器PrimitiveIterator.OfInt/Long/Double避免裝箱開銷,IntStream 等流底層使用。
可移除性檢測Iterator.remove() 默認拋異常不可變集合 (如 Collections.unmodifiableList) 迭代器調用 remove 拋 UnsupportedOperationException。

五、 迭代器 vs 索引遍歷:性能與適用場景

// 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) { ... }

六、 常見陷阱與避坑指南

  1. 遍歷中修改集合: 僅通過 iterator.remove() 安全刪除;新增/修改請收集索引/元素後二次處理,或使用 CopyOnWriteArrayList、ConcurrentHashMap 等並發容器。
  2. 迭代器重用: iterator() 每次返回**新實例**,不可重用舊迭代器遍歷新數據。
  3. Map 遍歷: Map 不實現 Iterable,**必須遍歷 entrySet() / keySet() / values()** (均實現 Iterable)。
  4. 泛型通配符: Iterable 只能讀取,Iterator 只能寫入 (PECS 原則)。
  5. Spliterator 特性標誌: ORDERED, DISTINCT, SORTED, SIZED, SUBSIZED, IMMUTABLE, CONCURRENT, NONNULL 影響流優化策略。

七、 總結

Iterable (容器契約) + Iterator (遍歷狀態封裝) 構成了 Java 統一遍歷抽象的基石。理解其介面契約、語法糖編譯、快速失效機制、JDK 8+ 默認方法增強、基本類型專用迭代器、Spliterator 並行分割原理,能讓你在集合選型、自定義容器開發、流式編程優化、並發安全遍歷等場景中游刃有餘。記住:**for-each 首選可讀性,性能敏感處 ArrayList 用索引,LinkedList/Set/Map 必用迭代器**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved