Java集合-Iterator(fast-fail)

之前分析了一些常用的集合,都繞過了迭代器這個概念利朵,這里重點分析一下迭代器相關的知識點。這里首先分析一下ArrayList的迭代器毛俏。

Iterator

首先看一下Iterator的定義:

public interface Iterator<E> {
    
    boolean hasNext();

    E next();

    void remove();
}

簡單的定義了Iterator的作用幅恋,就是一個迭代器杏死,迭代器最重要的就是兩個方法,判斷是否有寫一個元素hasNext()捆交,和獲取下一個元素next()淑翼。

接下來,會以ArrayList為例品追,介紹Iterator玄括,下面是會以ArrayList為例的介紹Iterator定義:

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;
}

該Iterator繼承了AbstractList的Iterator,其中cursor表示指向下一個元素的游標,lastRet指向上一個放回元素的游標肉瓦,初始情況下遭京,lastRet沒有曾經返回元素,所以初始化為-1泞莉,如圖:


ArrayList的Iterator

在每次迭代以前首先需要判斷當前是否還有未迭代的元素hasNext:

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

當游標順序循環(huán)迭代哪雕,迭代完最后一個元素時,游標的位置如圖:


遍歷完所有元素

此時的cursor指向數組的位置值恰好等于size戒财,所以此時沒有下一個元素可供迭代提取热监。

接下來看最重要的next()方法:

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];
}

首先checkForComodification()方法是運用了fast-fail機制,后面會單獨分析饮寞;然后:

int i = cursor;
if (i >= size)
    throw new NoSuchElementException();

將當前游標值存入到臨時變量i孝扛,并判斷游標值是否大于等于size的大辛泻稹(判斷依據參考上面所說的hasNext()),判斷游標是否越界了苦始;接著:

cursor = i + 1;
return (E) elementData[lastRet = i];

游標右移一位寞钥,同時返回原游標位置的元素,并把lastRet右移一位:

next

在List中陌选,還定義了一個ListIterator理郑, 他額外實現了向前查找元素,和添加元素的方法咨油,總體來看您炉,在實現原理上可以參考Iterator,這里就不重復分析了

fast-fail

快速失敗機制役电,在上面分析中提到了一個方法checkForComodification()赚爵,運用的就是快速失敗機制,那么在容器的jdk中能夠經撤ㄉ看到以下一段話(摘自arrayList):

 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
 * as it is, generally speaking, impossible to make any hard guarantees in the
 * presence of unsynchronized concurrent modification.  Fail-fast iterators
 * throw {@code ConcurrentModificationException} on a best-effort basis.
 * Therefore, it would be wrong to write a program that depended on this
 * exception for its correctness:  <i>the fail-fast behavior of iterators
 * should be used only to detect bugs.</i>

上面大概是說當并發(fā)迭代和結構修改時冀膝,迭代器會盡最大努力拋出 ConcurrentModificationException;具體舉例說霎挟,當線程A獲取當前容器的迭代器后窝剖,線程B對當前容器添加了一個元素(修改元素數據不會改變結構),線程A的跌打器就會檢測到數據結構被變更酥夭,并拋出ConcurrentModificationException赐纱。這就是fast-fail機制。
那么具體實現還是看ArrayList的代碼:

int expectedModCount = modCount;
final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
}

獲取迭代器的時候采郎,迭代器會得到當前容器的modCount修改次數千所,當每次檢查時,只需要看原來的修改次數是否與當前相同蒜埋,就可以知道淫痰,容器是否結構變更了。

for each

在jdk1.5以后整份,提供了對Collection的for each操作待错,通過使用for each的字節(jié)碼可以看到,for each實際是調用了iterator的實現去實現的烈评,這里就不重點分析字節(jié)碼火俄。這邊看一下HashMap的for each的三種實現:

public Set<K> keySet() {
    Set<K> ks = keySet;
    return (ks != null ? ks : (keySet = new KeySet()));
}
public Collection<V> values() {
    Collection<V> vs = values;
    return (vs != null ? vs : (values = new Values()));
}
public Set<Map.Entry<K,V>> entrySet() {
        return entrySet0();
}

private Set<Map.Entry<K,V>> entrySet0() {
    Set<Map.Entry<K,V>> es = entrySet;
    return es != null ? es : (entrySet = new EntrySet());
}

分別是遍歷鍵、值讲冠、鍵值對的方式瓜客,很多情況下,容易值遍歷key再取通過可以找value的情況,這樣的話谱仪,就多了一步get的過程玻熙,不如直接通過獲取entryset的效率高,需要注意就是這個情況疯攒。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末嗦随,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子敬尺,更是在濱河造成了極大的恐慌枚尼,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砂吞,死亡現場離奇詭異署恍,居然都是意外死亡,警方通過查閱死者的電腦和手機呜舒,發(fā)現死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門锭汛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袭蝗,你說我怎么就攤上這事“闫牛” “怎么了到腥?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蔚袍。 經常有香客問我乡范,道長,這世上最難降的妖魔是什么啤咽? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任晋辆,我火速辦了婚禮,結果婚禮上宇整,老公的妹妹穿的比我還像新娘瓶佳。我一直安慰自己,他們只是感情好鳞青,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布霸饲。 她就那樣靜靜地躺著,像睡著了一般臂拓。 火紅的嫁衣襯著肌膚如雪厚脉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天胶惰,我揣著相機與錄音傻工,去河邊找鬼。 笑死,一個胖子當著我的面吹牛中捆,可吹牛的內容都是我干的鸯匹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼轨香,長吁一口氣:“原來是場噩夢啊……” “哼忽你!你這毒婦竟也來了?” 一聲冷哼從身側響起臂容,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤科雳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后脓杉,有當地人在樹林里發(fā)現了一具尸體糟秘,經...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年球散,在試婚紗的時候發(fā)現自己被綠了尿赚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡蕉堰,死狀恐怖凌净,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情屋讶,我是刑警寧澤冰寻,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站皿渗,受9級特大地震影響斩芭,放射性物質發(fā)生泄漏。R本人自食惡果不足惜乐疆,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一划乖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挤土,春花似錦琴庵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至筒占,卻和暖如春贪庙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背翰苫。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工止邮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留这橙,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓导披,卻偏偏與公主長得像屈扎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子撩匕,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內容