做爲吃透Java集合的開篇,咱們從集合的最頂層接口(Iterable)擼起,經過本篇咱們要明白三個問題:
一、什麼是Iterable
二、什麼是Iterator
三、Iterable和Iterator有什麼關係數據結構
JDK描述:實現此接口容許對象成爲「 for-each循環」語句的目標。框架
那麼什麼是「 for-each循環」:「 for-each循環」是Java提供的語法糖,實際上仍是經過迭代器Iterator迭代遍歷,以下例子:ide
public static void main(String[] args) { List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3)); for (Integer i : list) { System.out.println(i); } }
編譯後的.class文件以下函數
public static void main(String[] args) { List<Integer> list = new ArrayList(Arrays.asList(1, 2, 3)); Iterator var2 = list.iterator(); while(var2.hasNext()) { Integer i = (Integer)var2.next(); System.out.println(i); } }
經過上面例子咱們明白了「 for-each循環」的本質。言歸正傳,接下來看Iterable源碼:ui
/** * 實現此接口容許對象成爲「 for-each循環」語句的目標 */ public interface Iterable<T> { /** * 返回類型爲{@code T}的元素上的迭代器。 */ Iterator<T> iterator(); /** * 對{@code Iterable} *的每一個元素執行給定的操做,直處處理完全部元素或該操做引起*異常爲止。除非實現類另行指定, * 不然*操做將以迭代順序執行(若是指定了迭代順序*) * * @since 1.8 JDK1.8新加的 */ default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } } /** * 在此* {@code Iterable}描述的元素上建立一個{@link Spliterator}。 * 默認實現從iterable的Iterator建立一個early-binding拼接器。 Spliter繼承了iterable的迭代器的fail-fast屬性。 * * @since 1.8 JDK1.8新加的 */ default Spliterator<T> spliterator() { return Spliterators.spliteratorUnknownSize(iterator(), 0); } }
Iterable中定義了三個函數,其中後面兩個是1.8新加的,具體分析一下這三個函數:this
iterator()返回迭代器實例,經過這個實例來實現對元素的遍歷,好比ArrayList中Itr內部類實現了iterator接口,關於iterator接口咱們後面會詳細分析。
forEach 對 Iterable 的每一個元素執行給定的操做,具體指定的操做須要本身寫Consumer接口經過accept方法回調出來。很簡單,咱們看一下例子就明白了設計
public static void main(String[] args) { List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3)); list.forEach(integer -> System.out.println(integer)); }
或者寫的更明白一些指針
public static void main(String[] args) { List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3)); list.forEach(new Consumer<Integer>() { @Override public void accept(Integer integer) { System.out.println(integer); } }); }
輸出結果爲:code
1 2 3 1 2 3
spliterator() 經過一個順序遍歷的Iterator對象獲取一個並行遍歷的Spliterator對象;
關於Spliterator:Spliterator(splitable iterator可分割迭代器)接口是Java爲了並行遍歷數據源中的元素而設計的迭代器,這個能夠類比最先Java提供的順序遍歷迭代器Iterator,但一個是順序遍歷,一個是並行遍歷。
對於Spliterator接口的設計思想,應該要提到的是Java7的Fork/Join(分支/合併)框架,總得來講就是用遞歸的方式把並行的任務拆分紅更小的子任務,而後把每一個子任務的結果合併起來生成總體結果。
關於Spliterator咱們先了解這麼多,畢竟不是這裏要介紹的重點。對象
Iterator是順序遍歷迭代器,jdk中默認對集合框架中數據結構作了實現。
Iterator在實際應用中有一個比較好的點就是,能夠一邊遍歷一遍刪除元素。
public interface Iterator<E> { /** * 若是被迭代遍歷的集合尚未被遍歷完,返回True */ boolean hasNext(); /** * 返回集合裏面的下一個元素 */ E next(); /** * 刪除集合裏面上一次next()方法返回的元素 * */ default void remove() { throw new UnsupportedOperationException("remove"); } /** * 對剩餘的每一個元素執行給定的操做,直到全部元素*已處理完畢或該操做引起異常。 * 若是指定了操做,則按迭代順序執行操做。操做引起的異常會中繼給調用者。 * @since 1.8 */ default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); } }
前三個函數沒什麼好說的,註釋已經說得很清楚了,那麼咱們來看一下最後一個函數
forEachRemaining與咱們剛纔瞭解的Iterable中的forEach有什麼區別呢?
forEachRemaining()方法內部是經過使用迭代器Iterator遍歷全部元素,forEach()方法內部使用的是加強for循環。
forEach()方法能夠屢次調用,forEachRemaining()方法第二次調用不會作任何操做,由於不會有下一個元素。
Iterator是迭代器接口,實現此接口的實例能夠對元素集合進行迭代遍歷,而Iterable是爲了只要實現該接口就可使用foreach進行迭代Iterable中封裝了Iterator接口,只要實現了Iterable接口的類,就可使用Iterator迭代器了。集合Collection、List、Set都是Iterable的實現類,因此他們及其餘們的子類均可以使用foreach進行迭代。Iterator中和核心的方法next(),hasnext(),remove(),都是依賴當前位置,若是這些集合直接實現Iterator,則必須包括當前迭代位置的指針。當集合在方法間進行傳遞的時候,因爲當前位置不可知,因此next()以後的值,也不可知。而當實現Iterable則否則,每次調用都返回一個從頭開始的迭代器,各個迭代器之間互不影響。