Iterator和Iterable解析


之前一直搞不清楚Iterator和Iterable到底有什么關系,它們的區別是什么,今天查看Java集合類源碼才發現其中的名堂,接下來給大家講講我的分析與理解。

Iterable接口

Iterable是接口,Iterable是1.5引入的新特性,Iterator是1.2就有了,二者都是為了迭代造作,Iterable只是包裝了Iterator,從而允許實現此接口的對象成為foreach語句的目標,而且這樣的話,更方便以后的擴展。

public interface Iterable<T> {
    /**
     * Returns an iterator over elements of type {@code T}.
     *
     * @return an Iterator.
     */
    Iterator<T> iterator();
   
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

Java集合Collection接口就擴展了Iterable接口。實現Iterable接口的那些類就可以擁有增強的for循環,該循環施于這些類之上以觀察他們所有的項。


public interface Collection<E> extends Iterable<E> {
    
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean removeAll(Collection<?> c);
    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
    boolean retainAll(Collection<?> c);
    void clear();
    boolean equals(Object o);
    int hashCode();
    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
}

實現Iterable接口的集合必須提供一個稱為itrator的方法,該方法又返回一個Iterator類型的對象。所以例如List集合類,Set類,他們實現了Collection接口,自然實現了Iterable接口,在其源碼中有具體的iterator方法,例如:ArraryList類中,它實現了List接口

    public Iterator<E> iterator() {
        return new Itr();
    }
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;
        
        public boolean hasNext() {
            return cursor != size;
        }
        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        ...

Iterator迭代器

Iterator接口的思路是,通過iterator方法,每個集合均可創建并返回給客戶一個實現Iterator接口的對象。

public interface Iterator<E> {
    boolean hasNext();
    T next();
    void remove();
}

Iterator一般用于簡單遍歷集合中的元素。而Iterator還有一個有用的方法叫做remove()方法,相對于Collection中的remove而言,它具有更多的優點。

對比Collection中remove方法和Iterator中remove方法

  • 抽象類AbstractCollection(實現了Collection接口)的remove方法
public boolean remove(Object o) {
        Iterator<E> it = iterator();
        if (o==null) {
            while (it.hasNext()) {
                if (it.next()==null) {
                    it.remove();
                    return true;
                }
            }
        } else {
            while (it.hasNext()) {
                //找出要被刪除的項
                if (o.equals(it.next())) {
                    it.remove();
                    return true;
                }
            }
        }
        return false;
    }

Collection的remove方法必須首先找出要被刪除的項,開銷較大。

  • Iterator中的remove方法
 private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;
        
    public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);//remove()方法下面有給出
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
    }
 }

以上是ArrayList中其實現Iterator接口的內部類中remove方法,可能其中有些變量你看不懂,需要聯系整個源碼才能夠明白它大體的意思。

以下是ArrayList重寫AbstractList中remove()方法。

public E remove(int index) {

        rangeCheck(index);//檢查是否越界

        modCount++;
        E oldValue = elementData(index);//得到要刪除的元素

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);//復制數組
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;//返回要刪除的元素
    }

不難看出Iterator的remove方法并沒有一個一個比較找出所要刪除的項,而是知道要刪除項的準確位置,那么刪除它的開銷就小很多。


使用Iterator的基本法則

如果對正在被迭代的集合進行結構上的改變(即對集合使用add,remove或clear方法),那么迭代器就不再合法(并且在其后使用該迭代器時將會有ConcurrentModificationException異常被拋出)。然而,如果迭代器調用了它自己的remove方法,那這個迭代器仍然是合法的,所以這是我們有時候更愿意使用迭代器的remove方法的第二個原因。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容

  • 1.Java集合框架是什么?說出一些集合框架的優點? 每種編程語言中都有集合,最初的Java版本包含幾種集合類:V...
    hutuxiaogui閱讀 680評論 0 10
  • Collection ├List │├LinkedList │├ArrayList │└Vector │└Stac...
    AndyZX閱讀 886評論 0 1
  • 1 場景問題# 1.1 工資表數據的整合## 考慮這樣一個實際應用:整合工資表數據。 這個項目的背景是這樣的,項目...
    七寸知架構閱讀 2,572評論 0 53
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,785評論 18 139
  • 頭馬圈是一群愛學習的人的天地,我們樂此不疲的參加各種活動。每當你付出一點,還能得到十點反饋,多值的交易。 為了增加...
    Tina新星閱讀 161評論 0 1