什麼?ArrayList我用增強for循環刪除居然沒報錯?

筆者在閱讀阿里巴巴Java開發手冊時看到這樣一段話:

不要在 foreach 循環裏進行元素的 remove/add 操作。remove 元素請使用Iterator 方式,如果併發操作,需要對 Iterator 對象加鎖
正例:

List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
	String item = iterator.next();
	if (刪除元素的條件) {
		iterator.remove();
	}
}
`反例:`

```java
for (String item : list) {
	if ("1".equals(item)) {
		list.remove(item);
	}
}

說明:以上代碼的執行結果肯定會出乎大家的意料,那麼試一下把“1”換成“2”,會是同樣的結果嗎?

筆者疑惑,什麼意思,難道不是所有的增強for刪除元素都會報錯嗎?記得是modCount != expectedModCount的時候會報錯呀

於是筆者實現了一下,發現…

        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");

        for (String item : list) {
            if ("1".equals(item)) {
                list.remove(item);
            }
        }
        System.out.println(list);

發現居然…
在這裏插入圖片描述
一條小綠條震驚了我
在這裏插入圖片描述
然後我執行第二套代碼,也就是把1換成2

        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");

        for (String item : list) {
            if ("2".equals(item)) {
                list.remove(item);
            }
        }
        System.out.println(list);

在這裏插入圖片描述
呼~報錯了,是我滿意的結果。

於是,我決定debug一下發生了什麼,第一套代碼爲什麼不會報錯呢。

首先進到remove方法
在這裏插入圖片描述
很合理,進到fastRemove方法了
在這裏插入圖片描述
modCount++,移動元素,讓空出的位置值null讓GC清理,很合理,1 被刪除了。
在這裏插入圖片描述
然後回來,return true,進行下一個遍歷。增強for是會用ArrayList的內部類,來判斷是否有下一個元素,cursor是一個遊標,判斷是否遍歷到頭了。在這裏插入圖片描述
可以看到,由於剛纔已經刪除了“1”,所以size爲1,而cursor由於是到索引1了,haxNext的判斷遊標與長度是相等的,在他看來遍歷結束了,返回false。於是遍歷結束,這樣還沒進入到modCount和expectedModCount的比較,遍歷就已經退出~

讓我們再來看看第二套代碼

由於第一個值是“1”,不相等,所以直接進入第二個循環

在這裏插入圖片描述
跟前面一樣,會用ArrayList的內部類判斷是否遍歷結束
在這裏插入圖片描述
這裏遊標爲1,size爲2,所以不相等,爲true

接下來是調用next方法,這個方法依舊是ArrayList的內部類Itr持有
在這裏插入圖片描述
進入checkForComodification方法
在這裏插入圖片描述
可以看到,由於之前沒有刪除操作,所以這一步是ok的,不會報錯。

繼續走next剩餘的方法,沒有問題。
在這裏插入圖片描述

接下來因爲相等了,執行remove方法在這裏插入圖片描述
在這裏插入圖片描述
執行fastRemove方法,modCount的值變化
在這裏插入圖片描述
然後增強for循環繼續
在這裏插入圖片描述
發現hasNext依舊成立,因爲遊標cursor爲2,而長度爲1
於是執行next方法,首先執行checkForComodification
在這裏插入圖片描述
modCount不等於expectedModCount,拋出異常
在這裏插入圖片描述

總結:
原來如此,代碼1之所以沒有報錯,原來是因爲它沒有進入到modCount和expectedModCount的判斷就結束了。但是隻要我們明確不能在增強for循環刪除、插入元素,還是ok的~。

果然,要了解底層,還是得自己看看源碼才知道。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章