吃透Java系列之Iterable和Iterator

前言:

做爲吃透Java集合的開篇,咱們從集合的最頂層接口(Iterable)擼起,經過本篇咱們要明白三個問題:
一、什麼是Iterable
二、什麼是Iterator
三、Iterable和Iterator有什麼關係數據結構

一:什麼是Iterable

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

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()方法第二次調用不會作任何操做,由於不會有下一個元素。

三:Iterable和Iterator有什麼關係

Iterator是迭代器接口,實現此接口的實例能夠對元素集合進行迭代遍歷,而Iterable是爲了只要實現該接口就可使用foreach進行迭代Iterable中封裝了Iterator接口,只要實現了Iterable接口的類,就可使用Iterator迭代器了。集合Collection、List、Set都是Iterable的實現類,因此他們及其餘們的子類均可以使用foreach進行迭代。Iterator中和核心的方法next(),hasnext(),remove(),都是依賴當前位置,若是這些集合直接實現Iterator,則必須包括當前迭代位置的指針。當集合在方法間進行傳遞的時候,因爲當前位置不可知,因此next()以後的值,也不可知。而當實現Iterable則否則,每次調用都返回一個從頭開始的迭代器,各個迭代器之間互不影響。

相關文章
相關標籤/搜索