在個人工做中,普遍使用了 List 類型的引用變量,而引用的是具體的類 ArrayList。咱們一般會使用 for 循環遍歷一個 List,每一次循環爲 List 調用的 get 方法傳入一個循環變量,這樣就取到了具體位置的元素,並進行業務上的處理。那麼,咱們爲何須要 Iterator 接口?php
經過 for 循環遍歷的方式,須要事先知道其內部結構,每種集合有各自的遍歷方法,由此產生的是訪問代碼和集合自己造成了緊耦合,不利於複用。想象一下,當初使用了 ArrayList 處理數據,而如今告訴你要使用 LinkedList,而你的業務代碼又複雜而繁瑣……好了,如今有了Iterator接口,你不再用關心你遍歷的集合的具體實現,統一經過調用 Iterator 的方法,使用同一種邏輯就能夠間接遍歷整個集合,何樂而不爲呢!java
迭代器模式,它提供一種方法順序訪問一個聚合對象中各個元素,而又不需暴露該對象的內部表示。具體的幾點要求:程序員
一、訪問一個聚合對象的內容而無需暴露它的內部表示;less
二、支持對聚合對象的多種遍歷;ui
三、爲遍歷不一樣的聚合結構提供一個統一的接口。this
Iterator 接口正是作到了這幾點,下面,看看 Iterator 接口定義的三個方法。spa
文檔:Returns true if the iteration has more elements. (In other words, returns true if next would return an element rather than throwing an exception.)指針
經常使用在 next 方法以前,用於判斷 next 方法是否能返回一個元素,不至於調用 next 方法是拋出異常。code
文檔:Returns the next element in the iteration.對象
文檔很容易理解,注意這裏使用了泛型就能夠了。
文檔:Removes from the underlying collection the last element returned by the iterator (optional operation). This method can be called only once per call to next. The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.
remove 方法將刪除最後一次使用 next 方法返回的元素,須要注意每次調用了 next 方法後,此方法只能被調用一次,不然拋出 IllegalStateException 異常。
若是進行迭代時用調用此方法以外的其餘方式修改了該迭代器所指向的collection,則迭代器的行爲是不肯定的。也就是說,在迭代時使用 remove 方法修改了迭代器指向的 collection,迭代器的行爲能肯定,但調用其它方法卻不是這樣的。
ListIterator 繼承了 Iterator。ListIterator 是系列表迭代器,容許程序員按任一方向遍歷列表、迭代期間修改列表,並得到迭代器在列表中的當前位置。ListIterator 沒有當前元素,它的光標位置始終位於調用 previous() 所返回的元素和調用 next() 所返回的元素之間。長度爲 n 的列表的迭代器有 n+1 個可能的指針位置(第一個元素以前和最後一個元素以後)。
下面逐一介紹 ListIterator 接口的方法:
一、void add(E e)
該方法能夠將指定的對象元素 e 加入到列表。須要特別留意元素被加入列表的位置:
(1)next 方法返回的下一個元素以前;
(2)previous 方法返回的下一個元素以後;
(3)列表爲空時,成爲列表惟一的元素。
二、boolean hasNext()
經常使用在 next 方法以前,用於判斷 next 方法是否能返回一個元素,不至於調用 next 方法是拋出異常。
三、boolean hasPrevious()
逆向遍歷列表方式下,用在 previous 方法以前,判斷 previous 方法是否能返回一個元素,而不是拋出異常。
四、E next()
返回列表中的下一個元素。
五、int nextIndex()
返回對 next 後續調用所返回元素的索引。
請看例子:
// 聲明一個List List<String> list = new ArrayList<String>(); // 添加元素 list.add("1"); list.add("2"); list.add("3"); // 獲取迭代器 ListIterator<String> li = list.listIterator(); // 迭代遍歷 while(li.hasNext()) { System.out.println(li.next() + ": " + li.nextIndex()); li.remove(); }
結果以下:
1: 1 2: 1 3: 1
可見 nextIndex 返回的是(next 所返回元素的索引 + 1)。若是當前 next 返回的元素是列表最後一個元素,那麼 nextIndex 返回的值就是整個列表的大小。
六、E previous()
返回列表中的上一個元素。
七、int previousIndex()
返回對 next 後續調用所返回元素的索引。
請看例子:
// 聲明List List<String> list = new ArrayList<String>(); // 添加元素 list.add("1"); list.add("2"); list.add("3"); // 獲取迭代器 ListIterator<String> li = list.listIterator(); // 正向遍歷 while(li.hasNext()) { System.out.println(li.next() + ": " + li.nextIndex()); } // 逆向遍歷 while(li.hasPrevious()) { System.out.println(li.previous() + ": " + li.previousIndex()); }
結果以下:
1: 1 2: 2 3: 3 3: 1 2: 0 1: -1
正向遍歷是爲了將光標移至列表尾部。可見,在逆向遍歷方式中,previousIndex 返回的是(previous 所返回元素的索引 - 1)。若是當前 previous 返回的是列表中第一個元素,那麼 previousIndex 返回的值等於-1。
八、void remove()
從列表中刪除 next 或 previous 返回的最後一個元素。每一次調用 next 或 previous 方法以後只能調用一次此方法,另外,若是有 add 方法調用,那麼 remove 方法必須在 add 方法以前被執行。
九、void set(E e)
set 方法提供的實際上是一個修改功能,它將指定的元素 e 替換 next 或 previous 返回的最後一個元素。
// 聲明List List<String> list = new ArrayList<String>(); // 添加元素 list.add("1"); list.add("2"); list.add("3"); // 獲取迭代器 ListIterator<String> li = list.listIterator(); // 正向遍歷並修改元素 System.out.println("修改前:"); while(li.hasNext()) { System.out.println(li.next()); li.set("4"); } // 逆向遍歷並輸出元素 System.out.println("修改後:"); while(li.hasPrevious()) { System.out.println(li.previous()); }
結果 修改前: 1 2 3 修改後: 4 4 4
Iterator接口中定義的三個方法都依賴於迭代器的當前迭代位置,若是讓這些集合直接實現 Iterator 接口,那麼這些集合接口和類中勢必須要定義一些儲存當前迭代位置的成員變量。由此而產生的問題是,當在多處使用一個集合時,因爲迭代位置的不肯定性,調用該集合的 next 方法時返回的結果也是不可預知的。
那麼有什麼辦法呢?Iterable接口爲咱們提供了一個 iterator 方法,每當調用該方法時,便會返回一個新的迭代器,而這些迭代器是互不干擾的,這樣即可以使用多個迭代器的方式來處理數據。若是但願更深一步研究Iterator和Iterable,能夠去研究研究JDK中是如何實現了Iterable接口的。
在CSDN論壇中一個關於二者區別的回答:
Iterable接口實現後的功能是「返回」一個迭代器,而Iterator接口實現後的功能是「使用」一個迭代器。
本文的例子中,用到了 iterator 方法,由於ArrayList 實現了Iterable接口,調用 iterator 方法返回一個迭代器,在對迭代器進行操做便可。
下面看看API中如何說明 iterator 方法:
Iterator<T> iterator() —— Returns an iterator over a set of elements of type T.