日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

大剑无锋之ArrayList中使用增强for循环能删除元素吗?【面试推荐】

發(fā)布時間:2024/2/28 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大剑无锋之ArrayList中使用增强for循环能删除元素吗?【面试推荐】 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

好久沒寫java代碼,前幾天面試被問到不少java的問題,其中一個接下來要說的。

先看幾段代碼。

第一段(集合中兩個元素,判斷條件是第一個元素)

ArrayList<String> list = new ArrayList<String>();list.add("george");list.add("georgedage");for (String s : list) {if ("george".equals(s)){list.remove(s);}}System.out.println(list);

輸出結(jié)果

[georgedage]

?第二段代碼(集合中兩個元素,判斷條件是第二個元素)

ArrayList<String> list = new ArrayList<String>();list.add("george");list.add("georgedage");for (String s : list) {if ("georgedage".equals(s)){ list.remove(s);}}System.out.println(list);

輸出結(jié)果


再看第三段代碼(集合中個元素,判斷條件是第一個元素)

ArrayList<String> list = new ArrayList<String>();list.add("george");list.add("georgedage");list.add("kangkang");for (String s : list) {if ("george".equals(s)){list.remove(s);}}System.out.println(list);

輸出結(jié)果


程序運(yùn)行結(jié)果為:當(dāng)集合中只有兩個元素,且判斷條件是第一個元素,remove方法執(zhí)行成功

當(dāng)集合中有兩個元素,且判斷條件是第二個元素,remove執(zhí)行拋出ConcurrentModificationException的異常

當(dāng)集合中有兩個以上元素(不包含兩個)時,判斷條件就算為第一個元素,remove執(zhí)行也拋出ConcurrentModificationException的異常

或許我們之前編寫代碼,或者看文檔時有了解過,對于集合的增加、刪除、修改元素,均不可以使用foreach(增強(qiáng)for循環(huán))

那么為什么呢?

接下來就讓我們走進(jìn)他的內(nèi)心世界!!!(源碼來襲,請睜大雙眼)

在進(jìn)入ArrayList中,我發(fā)現(xiàn)有forEach這個方法,但是我們都知道增強(qiáng)for循環(huán)對于集合的話,只適用于實現(xiàn)Iterable接口的集合上。那么增強(qiáng)for的底層究竟是什么?進(jìn)行一次反編譯。

實現(xiàn)原理

可以看到,增強(qiáng)For是JAVA提供的語法糖,這里我們剖析一下,這種增強(qiáng)for循環(huán)底層是如何實現(xiàn)的。

我們對以下代碼進(jìn)行反編譯:

1

2

3

for (Integer i : list) {

?System.out.println(i);

}

反編譯后:

1

2

3

4

Integer i;

for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){

?i = (Integer)iterator.next();

}

反編譯后的代碼其實比較復(fù)雜,我們按照執(zhí)行順序拆解一下:

Integer i; 定義一個臨時變量i
Iterator iterator = list.iterator(); 獲取List的迭代器
iterator.hasNext(); 判斷迭代器中是否有未遍歷過的元素
i = (Integer)iterator.next(); 獲取第一個未遍歷的元素,賦值給臨時變量i
System.out.println(i) 輸出臨時變量i的值

如此循環(huán)往復(fù),直到遍歷完List中的所有元素。

通過反編譯,我們看到,其實JAVA中的增強(qiáng)for循環(huán)底層是通過迭代器模式來實現(xiàn)的。

這也就說通我們上面代碼中所踩的坑

既然增強(qiáng)for循環(huán)通過迭代器實現(xiàn),那么必然有迭代器的特性。

Java中有fail-fast機(jī)制。在使用迭代器遍歷元素的時候,在對集合進(jìn)行刪除的時候一定要注意,使用不當(dāng)有可能發(fā)生ConcurrentModificationException,這是一種運(yùn)行時異常,編譯期并不會發(fā)生。只有在程序真正運(yùn)行時才會爆發(fā)。

如以下代碼:

1

2

3

4

for (Student stu : students) {

?if (stu.getId() == 2)

?students.remove(stu);

}

會拋出ConcurrentModificationException異常。

Iterator是工作在一個獨立的線程中,并且擁有一個 mutex 鎖。 Iterator被創(chuàng)建之后會建立一個指向原來對象的單鏈索引表,當(dāng)原來的對象數(shù)量發(fā)生變化時,這個索引表的內(nèi)容不會同步改變,所以當(dāng)索引指針往后移動的時候就找不到要迭代的對象,所以按照 fail-fast 原則 Iterator 會馬上拋出java.util.ConcurrentModificationException異常。

所以 Iterator 在工作的時候是不允許被迭代的對象被改變的。

在源碼中這樣展示:

private class Itr implements Iterator<E> {int cursor; // index of next element to returnint lastRet = -1; // index of last element returned; -1 if no suchint 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];}

在第一段代碼中,為什么能remove成功呢,其實它只循環(huán)了一次,所以成功了。

因為它在remove元素1之后,它的size - 1變成1,然后Itr內(nèi)部的cursor變量由0變成1
此時1 = 1,循環(huán)結(jié)束,所以成功了。

arraylist2為什么remove失敗呢,因為他在循環(huán)第二次的時候,也remove成功了,但是第三次判斷next的時候cursor的值為2導(dǎo)致不等于現(xiàn)在的size 1,所以執(zhí)行了next方法,最重要的來了,之前remove的操作導(dǎo)致ArrayList的modCount值加1,然后Itr類中的expectedModCount保持不變,所以會拋出異常。

因此得出結(jié)論:

不允許在foreach中刪除、增加、修改ArrayList中的元素。

正確的在遍歷的同時刪除元素的姿勢:

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

當(dāng)然如果存在并發(fā)操作,還需要對Iterator進(jìn)行加鎖操作。

撤了撤了,如果還有什么好的建議,互相交流一下!!!

總結(jié)

以上是生活随笔為你收集整理的大剑无锋之ArrayList中使用增强for循环能删除元素吗?【面试推荐】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。