Java集合框架概覽以及迭代器

目錄介紹

  • 1.什么是集合
    • 1.1 概念
    • 1.2 和數(shù)組區(qū)別
    • 1.3 java集合框架圖
  • 2.Iterator、Iterable和ListIterator
    • 2.1 簡介
    • 2.2 Iterable接口
    • 2.3 Iterator接口
    • 2.4 ListIterator接口
  • 3.Iterable和ListIterator具體實(shí)現(xiàn)(以ArrayList為例)
    • 3.1 Iterable具體實(shí)現(xiàn)----Itr
    • 3.2 ListIterator具體實(shí)現(xiàn)----ListItr
  • 4.fail-fast機(jī)制
    • 4.1 簡介
    • 4.2 如何邊遍歷邊操作集合

1.什么是集合

1.1 概念

  • java集合框架的用途是“保存對象”首妖,并將其劃分為兩個不同的概念:
  • (1)Collection破衔。 一個獨(dú)立的元素序列冠王,這些元素都服從一條或多條規(guī)則澄暮。List必須按照插入的順序保存元素月帝,而Set不能有重復(fù)的元素搅荞。Queue按照排隊(duì)的規(guī)則來確定對象的產(chǎn)生順序(通常與他們被插入的順序相同)
  • (2)Map。一組成對的“鍵值對”對象框咙,允許你使用鍵來查找值咕痛。

1.2 集合和數(shù)組的區(qū)別

  • (1)數(shù)組長度固定,集合長度不固定
  • (2)數(shù)組可以儲存基本數(shù)據(jù)類型和引用數(shù)據(jù)類型喇嘱,集合只能存儲引用數(shù)據(jù)類型

1.3 java集合框架圖

下圖是java集合框架的總圖:


java集合框架.png

2.Iterator茉贡、Iterable和ListIterator

2.1 簡介

Collection是java序列集合的根接口,繼承Iterable接口者铜;Iterable接口提供foreach能力腔丧,并且要求實(shí)現(xiàn)者返回一個Iterator,從本質(zhì)上來說Iterator是java序列容器之間的共性作烟,AbstractCollection等抽象類都是通過Iterator來實(shí)現(xiàn)collection接口的方法愉粤,由于java的單繼承性,我們的類在已經(jīng)繼承其他類的基礎(chǔ)上拿撩,不能再繼承AbstractCollection衣厘;而繼承Collection代價又略微偏高,可以通過實(shí)現(xiàn)Iterable接口來實(shí)現(xiàn)一個Collection压恒。

2.2 Iterable接口

Iterable接口是Collection接口的父接口影暴,他要求實(shí)現(xiàn)類返回一個迭代器,并且提供foreach遍歷的能力探赫。

public interface Iterable<T> {
    // 返回一個在一組 T 類型的元素上進(jìn)行迭代的迭代器型宙。
    Iterator<T> iterator();  
    // foreach遍歷
    default void forEach(Consumer<? super T> action) {}
    // 返回一個可分割的迭代器
    default Spliterator<T> spliterator() {
    return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

2.3 Iterator接口

Iterator接口的定義也十分簡單,提供迭代器往后面元素迭代的能力

public interface Iterator<E> {
    // 是否還有元素可以迭代
    boolean hasNext();
    // 返回迭代的下一個元素
    E next();
    // 移除迭代器返回的最后一個元素
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    // 對剩下的元素執(zhí)行給定操作
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
        action.accept(next());
    }
}

2.4 ListIterator接口

ListIterator是List集合特有的迭代器

public interface ListIterator<E> extends Iterator<E> {
    boolean hasNext();
    E next();
    // 判斷游標(biāo)前面是否有元素
    boolean hasPrevious();
    // 返回游標(biāo)前面的元素伦吠,同時游標(biāo)前移一位妆兑。
    E previous();
    // 返回游標(biāo)后邊元素的索引位置,初始為0
    int nextIndex();
    // 返回游標(biāo)前面元素的位置毛仪,初始時為-1
    int previousIndex();
    // 刪除迭代器最后一次操作的元素
    void remove();
    // 更新迭代器最后一次操作的元素為 E
    void set(E e);
    // 在游標(biāo)前面插入一個元素
    void add(E e);
}

3.Iterable和ListIterator具體實(shí)現(xiàn)(以ArrayList為例)

3.1 Iterable具體實(shí)現(xiàn)----Itr

private class Itr implements Iterator<E> {
    // 游標(biāo)位置
    int cursor;
    // 上次迭代的位置       
    int lastRet = -1;
    // 用來判斷是否fail-fast的變量
    int expectedModCount = modCount;

    Itr() {}
         
     public boolean hasNext() {
        return cursor != size;
    }

        
    public E next() {
        // fail-fast校驗(yàn)
        checkForComodification();
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        // 游標(biāo)+1
        cursor = i + 1;
        // 更新lastRet并且返回對應(yīng)元素
        return (E) elementData[lastRet = i];
    }

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            // 調(diào)用外部類的remove方法移除元素
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            // 更新expectedModCount
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    // fail-fast校驗(yàn)
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
    }

3.2 ListIterator具體實(shí)現(xiàn)----ListItr

ListItr的實(shí)現(xiàn)也并不復(fù)雜箭跳,主要是對游標(biāo)進(jìn)行操作,這里關(guān)注一下set()和add()方法的實(shí)現(xiàn)潭千,可以看到方法內(nèi)部也對expectedModCount進(jìn)行了更新谱姓,所以他們也是可以幫助我們完成遍歷時對容器的操作的.

private class ListItr extends Itr implements ListIterator<E> {
    ListItr(int index) {
        super();
        cursor = index;
    }

    public boolean hasPrevious() {
        return cursor != 0;
    }

    public int nextIndex() {
        return cursor;
    }

    public int previousIndex() {
        return cursor - 1;
    }

    public E previous() {
        checkForComodification();
        int i = cursor - 1;
        if (i < 0)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i;
        return (E) elementData[lastRet = i];
    }

    public void set(E e) {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            ArrayList.this.set(lastRet, e);
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    public void add(E e) {
        checkForComodification();

        try {
            int i = cursor;
            ArrayList.this.add(i, e);
            cursor = i + 1;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    }

4.fail-fast機(jī)制

4.1 簡介

我們在使用Iterator對容器進(jìn)行迭代時如果修改容器,可能會導(dǎo)致ConcurrentModificationException異常刨晴。這是因?yàn)樵谖覀兊娜萜黝愔芯S護(hù)了一個int型的成員變量modCount屉来,每次對容器進(jìn)行操作時路翻,都會使modCount自增,而在Iterator接口的實(shí)現(xiàn)類中茄靠,有一個變量expectedModCount茂契,在遍歷開始時初始化賦值為modCount。每次遍歷時慨绳,都會去比較expectedModCount和modCount是否相等掉冶,如果不等,就會拋出異常脐雪。這就是java的fail-fast機(jī)制厌小,該機(jī)制主要是用于實(shí)現(xiàn)集合的快速失敗機(jī)制,在Java的集合中战秋,較大一部分集合是存在快速失敗機(jī)制的璧亚。所以要保證在遍歷過程中不出錯誤,我們就應(yīng)該保證在遍歷過程中不會對集合產(chǎn)生結(jié)構(gòu)上的修改脂信,出現(xiàn)了異常錯誤癣蟋,我們就應(yīng)該認(rèn)真檢查程序是否出錯而不是catch后不做處理。

// ArrayList中移除元素時modCount自增
public E remove(int index) {
    rangeCheck(index);
    // modCount自增
    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;
}
// ArrayList中Itr校驗(yàn)modCount
final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

4.2 如何邊遍歷邊操作集合
這里推薦使用迭代器iterator提供的方法進(jìn)行操作容器狰闪,當(dāng)然疯搅,也有其他方式能夠解決這個問題,比如說在遍歷時刪除元素可以采用倒序遍歷的方式埋泵,但是都不夠通用秉撇。

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String next = iterator.next();
    if (next.equals("dd")) {
        iterator.remove();
    }
}

之所以我們能夠這樣操作的原因是因?yàn)樵诘鞣椒▋?nèi)部,對expectedModCount進(jìn)行了重新賦值秋泄,使得下一次遍歷的時候琐馆,expectedModCount是等于modCount的.

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        // expectedModCount重新賦值
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恒序,隨后出現(xiàn)的幾起案子瘦麸,更是在濱河造成了極大的恐慌,老刑警劉巖歧胁,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滋饲,死亡現(xiàn)場離奇詭異,居然都是意外死亡喊巍,警方通過查閱死者的電腦和手機(jī)屠缭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來崭参,“玉大人呵曹,你說我怎么就攤上這事。” “怎么了奄喂?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵铐殃,是天一觀的道長。 經(jīng)常有香客問我跨新,道長富腊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任域帐,我火速辦了婚禮赘被,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肖揣。我一直安慰自己民假,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布许饿。 她就那樣靜靜地躺著,像睡著了一般舵盈。 火紅的嫁衣襯著肌膚如雪陋率。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天秽晚,我揣著相機(jī)與錄音瓦糟,去河邊找鬼。 笑死赴蝇,一個胖子當(dāng)著我的面吹牛菩浙,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播句伶,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼劲蜻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了考余?” 一聲冷哼從身側(cè)響起先嬉,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎楚堤,沒想到半個月后疫蔓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡身冬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年衅胀,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酥筝。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡滚躯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哀九,我是刑警寧澤剿配,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站阅束,受9級特大地震影響呼胚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜息裸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一蝇更、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧呼盆,春花似錦年扩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至腿时,卻和暖如春况脆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背批糟。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工格了, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人徽鼎。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓盛末,卻偏偏與公主長得像,于是被迫代替她去往敵國和親否淤。 傳聞我的和親對象是個殘疾皇子悄但,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容