# 遍歷聚合對象中的元素——迭代器模式(五)
5 JDK內置迭代器
為了讓開發人員能夠更加方便地操作聚合對象,在Java、C#等編程語言中都提供了內置迭代器。在Java集合框架中,常用的List和Set等聚合類都繼承(或實現)了java.util.Collection接口,在Collection接口中聲明了如下方法(部分):
```
package java.util;
public interface Collection<E> extends Iterable<E> {
……
boolean add(Object c);
boolean addAll(Collection c);
boolean remove(Object o);
boolean removeAll(Collection c);
boolean remainAll(Collection c);
Iterator iterator();
……
}
```
除了包含一些增加元素和刪除元素的方法外,還提供了一個iterator()方法,用于返回一個Iterator迭代器對象,以便遍歷聚合中的元素;具體的Java聚合類可以通過實現該iterator()方法返回一個具體的Iterator對象。
JDK中定義了抽象迭代器接口Iterator,代碼如下所示:
```
package java.util;
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
```
其中,hasNext()用于判斷聚合對象中是否還存在下一個元素,為了不拋出異常,在每次調用next()之前需先調用hasNext(),如果有可供訪問的元素,則返回true;next()方法用于將游標移至下一個元素,通過它可以逐個訪問聚合中的元素,它返回游標所越過的那個元素的引用;remove()方法用于刪除上次調用next()時所返回的元素。
Java迭代器工作原理如圖5所示,在第一個next()方法被調用時,迭代器游標由“元素1”與“元素2”之間移至“元素2”與“元素3”之間,跨越了“元素2”,因此next()方法將返回對“元素2”的引用;在第二個next()方法被調用時,迭代器由“元素2”與“元素3”之間移至“元素3”和“元素4”之間,next()方法將返回對“元素3”的引用,如果此時調用remove()方法,即可將“元素3”刪除。

圖5 Java迭代器示意圖
如下代碼片段可用于刪除聚合對象中的第一個元素:
```
Iterator iterator = collection.iterator(); //collection是已實例化的聚合對象
iterator.next(); // 跳過第一個元素
iterator.remove(); // 刪除第一個元素
```
需要注意的是,在這里,next()方法與remove()方法的調用是相互關聯的。如果調用remove()之前,沒有先對next()進行調用,那么將會拋出一個IllegalStateException異常,因為沒有任何可供刪除的元素。
如下代碼片段可用于刪除兩個相鄰的元素:
```
iterator.remove();
iterator.next(); //如果刪除此行代碼程序將拋異常
iterator.remove();
```
在上面的代碼片段中如果將代碼iterator.next();去掉則程序運行拋異常,因為第二次刪除時將找不到可供刪除的元素。
在JDK中,Collection接口和Iterator接口充當了迭代器模式的抽象層,分別對應于抽象聚合類和抽象迭代器,而Collection接口的子類充當了具體聚合類,下面以List為例加以說明,圖6列出了JDK中部分與List有關的類及它們之間的關系:

圖6 Java集合框架中部分類結構圖
(注:為了簡化類圖,本圖省略了大量方法)
在JDK中,實際情況比圖6要復雜很多,在圖6中,List接口除了繼承Collection接口的iterator()方法外,還增加了新的工廠方法listIterator(),專門用于創建ListIterator類型的迭代器,在List的子類LinkedList中實現了該方法,可用于創建具體的ListIterator子類ListItr的對象,代碼如下所示:
```
public ListIterator<E> listIterator(int index) {
return new ListItr(index);
}
listIterator()方法用于返回具體迭代器ListItr類型的對象。在JDK源碼中,AbstractList中的iterator()方法調用了listIterator()方法,如下代碼所示:
```
public Iterator<E> iterator() {
return listIterator();
}
```
客戶端通過調用LinkedList類的iterator()方法,即可得到一個專門用于遍歷LinkedList的迭代器對象。
大家可能會問?既然有了iterator()方法,為什么還要提供一個listIterator()方法呢?這兩個方法的功能不會存在重復嗎?干嘛要多此一舉?
這是一個好問題。我給大家簡單解釋一下為什么要這樣設計:由于在Iterator接口中定義的方法太少,只有三個,通過這三個方法只能實現正向遍歷,而有時候我們需要對一個聚合對象進行逆向遍歷等操作,因此在JDK的ListIterator接口中聲明了用于逆向遍歷的hasPrevious()和previous()等方法,如果客戶端需要調用這兩個方法來實現逆向遍歷,就不能再使用iterator()方法來創建迭代器了,因為此時創建的迭代器對象是不具有這兩個方法的。我們只能通過如下代碼來創建ListIterator類型的迭代器對象:
```
ListIterator i = c.listIterator();
```
正因為如此,在JDK的List接口中不得不增加對listIterator()方法的聲明,該方法可以返回一個ListIterator類型的迭代器,ListIterator迭代器具有更加強大的功能。
思考
為什么使用iterator()方法創建的迭代器無法實現逆向遍歷?
在Java語言中,我們可以直接使用JDK內置的迭代器來遍歷聚合對象中的元素,下面的代碼演示了如何使用Java內置的迭代器:
```
import java.util.*;
class IteratorDemo {
public static void process(Collection c) {
Iterator i = c.iterator(); //創建迭代器對象
//通過迭代器遍歷聚合對象
while(i.hasNext()) {
System.out.println(i.next().toString());
}
}
public static void main(String args[]) {
Collection persons;
persons = new ArrayList(); //創建一個ArrayList類型的聚合對象
persons.add("張無忌");
persons.add("小龍女");
persons.add("令狐沖");
persons.add("韋小寶");
persons.add("袁紫衣");
persons.add("小龍女");
process(persons);
}
}
```
在靜態方法process()中使用迭代器Iterator對Collection對象進行處理,該代碼運行結果如下:
```
張無忌
小龍女
令狐沖
韋小寶
袁紫衣
小龍女
```
如果需要更換聚合類型,如將List改成Set,則只需更換具體聚合類類名,如將上述代碼中的ArrayList改為HashSet,則輸出結果如下:
```
令狐沖
張無忌
韋小寶
小龍女
袁紫衣
```
在HashSet中合并了重復元素,并且元素以隨機次序輸出,其結果與使用ArrayList不相同。由此可見,通過使用迭代器模式,使得更換具體聚合類變得非常方便,而且還可以根據需要增加新的聚合類,新的聚合類只需要實現Collection接口,無須修改原有類庫代碼,符合“開閉原則”。
練習
> 在Sunny軟件公司開發的某教務管理系統中,一個班級(Class in School)包含多個學生(Student),使用Java內置迭代器實現對學生信息的遍歷,要求按學生年齡由大到小的次序輸出學生信息。
- Introduction
- 基礎知識
- 設計模式概述
- 從招式與內功談起——設計模式概述(一)
- 從招式與內功談起——設計模式概述(二)
- 從招式與內功談起——設計模式概述(三)
- 面向對象設計原則
- 面向對象設計原則之單一職責原則
- 面向對象設計原則之開閉原則
- 面向對象設計原則之里氏代換原則
- 面向對象設計原則之依賴倒轉原則
- 面向對象設計原則之接口隔離原則
- 面向對象設計原則之合成復用原則
- 面向對象設計原則之迪米特法則
- 六個創建型模式
- 簡單工廠模式-Simple Factory Pattern
- 工廠三兄弟之簡單工廠模式(一)
- 工廠三兄弟之簡單工廠模式(二)
- 工廠三兄弟之簡單工廠模式(三)
- 工廠三兄弟之簡單工廠模式(四)
- 工廠方法模式-Factory Method Pattern
- 工廠三兄弟之工廠方法模式(一)
- 工廠三兄弟之工廠方法模式(二)
- 工廠三兄弟之工廠方法模式(三)
- 工廠三兄弟之工廠方法模式(四)
- 抽象工廠模式-Abstract Factory Pattern
- 工廠三兄弟之抽象工廠模式(一)
- 工廠三兄弟之抽象工廠模式(二)
- 工廠三兄弟之抽象工廠模式(三)
- 工廠三兄弟之抽象工廠模式(四)
- 工廠三兄弟之抽象工廠模式(五)
- 單例模式-Singleton Pattern
- 確保對象的唯一性——單例模式 (一)
- 確保對象的唯一性——單例模式 (二)
- 確保對象的唯一性——單例模式 (三)
- 確保對象的唯一性——單例模式 (四)
- 確保對象的唯一性——單例模式 (五)
- 原型模式-Prototype Pattern
- 對象的克隆——原型模式(一)
- 對象的克隆——原型模式(二)
- 對象的克隆——原型模式(三)
- 對象的克隆——原型模式(四)
- 建造者模式-Builder Pattern
- 復雜對象的組裝與創建——建造者模式(一)
- 復雜對象的組裝與創建——建造者模式(二)
- 復雜對象的組裝與創建——建造者模式(三)
- 七個結構型模式
- 適配器模式-Adapter Pattern
- 不兼容結構的協調——適配器模式(一)
- 不兼容結構的協調——適配器模式(二)
- 不兼容結構的協調——適配器模式(三)
- 不兼容結構的協調——適配器模式(四)
- 橋接模式-Bridge Pattern
- 處理多維度變化——橋接模式(一)
- 處理多維度變化——橋接模式(二)
- 處理多維度變化——橋接模式(三)
- 處理多維度變化——橋接模式(四)
- 組合模式-Composite Pattern
- 樹形結構的處理——組合模式(一)
- 樹形結構的處理——組合模式(二)
- 樹形結構的處理——組合模式(三)
- 樹形結構的處理——組合模式(四)
- 樹形結構的處理——組合模式(五)
- 裝飾模式-Decorator Pattern
- 擴展系統功能——裝飾模式(一)
- 擴展系統功能——裝飾模式(二)
- 擴展系統功能——裝飾模式(三)
- 擴展系統功能——裝飾模式(四)
- 外觀模式-Facade Pattern
- 深入淺出外觀模式(一)
- 深入淺出外觀模式(二)
- 深入淺出外觀模式(三)
- 享元模式-Flyweight Pattern
- 實現對象的復用——享元模式(一)
- 實現對象的復用——享元模式(二)
- 實現對象的復用——享元模式(三)
- 實現對象的復用——享元模式(四)
- 實現對象的復用——享元模式(五)
- 代理模式-Proxy Pattern
- 設計模式之代理模式(一)
- 設計模式之代理模式(二)
- 設計模式之代理模式(三)
- 設計模式之代理模式(四)
- 十一個行為型模式
- 職責鏈模式-Chain of Responsibility Pattern
- 請求的鏈式處理——職責鏈模式(一)
- 請求的鏈式處理——職責鏈模式(二)
- 請求的鏈式處理——職責鏈模式(三)
- 請求的鏈式處理——職責鏈模式(四)
- 命令模式-Command Pattern
- 請求發送者與接收者解耦——命令模式(一)
- 請求發送者與接收者解耦——命令模式(二)
- 請求發送者與接收者解耦——命令模式(三)
- 請求發送者與接收者解耦——命令模式(四)
- 請求發送者與接收者解耦——命令模式(五)
- 請求發送者與接收者解耦——命令模式(六)
- 解釋器模式-Interpreter Pattern
- 自定義語言的實現——解釋器模式(一)
- 自定義語言的實現——解釋器模式(二)
- 自定義語言的實現——解釋器模式(三)
- 自定義語言的實現——解釋器模式(四)
- 自定義語言的實現——解釋器模式(五)
- 自定義語言的實現——解釋器模式(六)
- 迭代器模式-Iterator Pattern
- 遍歷聚合對象中的元素——迭代器模式(一)
- 遍歷聚合對象中的元素——迭代器模式(二)
- 遍歷聚合對象中的元素——迭代器模式(三)
- 遍歷聚合對象中的元素——迭代器模式(四)
- 遍歷聚合對象中的元素——迭代器模式(五)
- 遍歷聚合對象中的元素——迭代器模式(六)
- 中介者模式-Mediator Pattern
- 協調多個對象之間的交互——中介者模式(一)
- 協調多個對象之間的交互——中介者模式(二)
- 協調多個對象之間的交互——中介者模式(三)
- 協調多個對象之間的交互——中介者模式(四)
- 協調多個對象之間的交互——中介者模式(五)
- 備忘錄模式-Memento Pattern
- 撤銷功能的實現——備忘錄模式(一)
- 撤銷功能的實現——備忘錄模式(二)
- 撤銷功能的實現——備忘錄模式(三)
- 撤銷功能的實現——備忘錄模式(四)
- 撤銷功能的實現——備忘錄模式(五)
- 觀察者模式-Observer Pattern
- 對象間的聯動——觀察者模式(一)
- 對象間的聯動——觀察者模式(二)
- 對象間的聯動——觀察者模式(三)
- 對象間的聯動——觀察者模式(四)
- 對象間的聯動——觀察者模式(五)
- 對象間的聯動——觀察者模式(六)
- 狀態模式-State Pattern
- 處理對象的多種狀態及其相互轉換——狀態模式(一)
- 處理對象的多種狀態及其相互轉換——狀態模式(二)
- 處理對象的多種狀態及其相互轉換——狀態模式(三)
- 處理對象的多種狀態及其相互轉換——狀態模式(四)
- 處理對象的多種狀態及其相互轉換——狀態模式(五)
- 處理對象的多種狀態及其相互轉換——狀態模式(六)
- 策略模式-Strategy Pattern
- 算法的封裝與切換——策略模式(一)
- 算法的封裝與切換——策略模式(二)
- 算法的封裝與切換——策略模式(三)
- 算法的封裝與切換——策略模式(四)
- 模板方法模式-Template Method Pattern
- 模板方法模式深度解析(一)
- 模板方法模式深度解析(二)
- 模板方法模式深度解析(三)
- 訪問者模式-Visitor Pattern
- 操作復雜對象結構——訪問者模式(一)
- 操作復雜對象結構——訪問者模式(二)
- 操作復雜對象結構——訪問者模式(三)
- 操作復雜對象結構——訪問者模式(四)
- 設計模式趣味學習(復習)
- 設計模式與足球(一)
- 設計模式與足球(二)
- 設計模式與足球(三)
- 設計模式與足球(四)
- 設計模式綜合應用實例
- 多人聯機射擊游戲
- 多人聯機射擊游戲中的設計模式應用(一)
- 多人聯機射擊游戲中的設計模式應用(二)
- 數據庫同步系統
- 設計模式綜合實例分析之數據庫同步系統(一)
- 設計模式綜合實例分析之數據庫同步系統(二)
- 設計模式綜合實例分析之數據庫同步系統(三)