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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

编程问答

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

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

好久沒(méi)寫java代碼,前幾天面試被問(wèn)到不少java的問(wèn)題,其中一個(gè)接下來(lái)要說(shuō)的。

先看幾段代碼。

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

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]

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

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é)果


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

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)集合中只有兩個(gè)元素,且判斷條件是第一個(gè)元素,remove方法執(zhí)行成功

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

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

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

那么為什么呢?

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

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

實(shí)現(xiàn)原理

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

我們對(duì)以下代碼進(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();

}

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

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

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

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

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

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

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

如以下代碼:

1

2

3

4

for (Student stu : students) {

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

?students.remove(stu);

}

會(huì)拋出ConcurrentModificationException異常。

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

所以 Iterator 在工作的時(shí)候是不允許被迭代的對(duì)象被改變的。

在源碼中這樣展示:

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成功呢,其實(shí)它只循環(huán)了一次,所以成功了。

因?yàn)樗趓emove元素1之后,它的size - 1變成1,然后Itr內(nèi)部的cursor變量由0變成1
此時(shí)1 = 1,循環(huán)結(jié)束,所以成功了。

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

因此得出結(jié)論:

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

正確的在遍歷的同時(shí)刪除元素的姿勢(shì):

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

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

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

總結(jié)

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

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