Java?ArrayList遍歷foreach與iterator時(shí)remove的區(qū)別
一、Iterator和foreach的區(qū)別
- 多態(tài)差別(foreach底層就是Iterator)
- Iterator是一個(gè)接口類(lèi)型,他不關(guān)心集合或者數(shù)組的類(lèi)型;
- for和foreach都需要先知道集合的類(lèi)型,甚至是集合內(nèi)元素的類(lèi)型;
1.為啥說(shuō)foreach底層就是Iterator
編寫(xiě)的代碼:
反編譯代碼:
二、foreach與iterator時(shí)remove的區(qū)別
先來(lái)看阿里java開(kāi)發(fā)手冊(cè)
但1的時(shí)候不會(huì)報(bào)錯(cuò),2的時(shí)候就會(huì)報(bào)錯(cuò)(java.util.ConcurrentModificationException)
首先來(lái)看一下ArrayList中iterator方法的實(shí)現(xiàn):
調(diào)用了new Itr(),生成Itr類(lèi)(迭代器)。此時(shí)會(huì)給Itr的三個(gè)參數(shù)初始化。
- cursor代表下一次的索引位置(開(kāi)始是0)
- size是集合的大小(2)
拋出異常類(lèi)
next方法()的時(shí)候會(huì)檢查checkForComodification是否相等
modCount修改計(jì)數(shù)(每次add和remove都會(huì)+1)expectedModCount期望的最大計(jì)數(shù)
1.remove操作源碼分析
首先來(lái)看一下刪除“2”的情況:
第一次循環(huán):
因?yàn)榇藭r(shí)的modCount和expectedModCount都為2(因?yàn)閍dd了兩次所以modCount為2),所以第一次循環(huán)中不會(huì)拋出異常,拋出異常都是發(fā)生在不是第一次循環(huán)的情況中。在next方法走完后,foreach循環(huán)方法體中的remove方法的if條件判斷不滿(mǎn)足,就結(jié)束了本次循環(huán)。
第二次循環(huán):
第二次循環(huán)的hasNext和next方法都是能成功走完的,在這之后會(huì)進(jìn)入到foreach循環(huán)方法體中的remove方法中,進(jìn)行刪除元素。而此時(shí)的size-1變?yōu)榱?。在remove方法中的fastRemove方法中,會(huì)對(duì)modCount+1,也就變?yōu)榱?。
第三次循環(huán):
然后會(huì)走入到第三次循環(huán)中的hasNext方法中。按照正常的情況下該方法是會(huì)返回false的,但因?yàn)榇藭r(shí)的size已經(jīng)變?yōu)榱?,而此時(shí)的cursor為2(cursor代表下一次的索引位置),所以?xún)烧卟坏?,錯(cuò)誤地返回了true,所以會(huì)繼續(xù)走入到next方法中的checkForComodification方法中,判斷此時(shí)的modCount和expectedModCount是否相等。因?yàn)榇藭r(shí)的modCount已經(jīng)變?yōu)榱?,和expectedModCount的值為2不等,所以在此拋出了ConcurrentModificationException異常。
再來(lái)看一下刪除“1”的時(shí)候?yàn)槭裁床粫?huì)拋出異常:
第一次循環(huán):
同上,此時(shí)的modCount和expectedModCount都為2,所以第一次循環(huán)中的hasNext和next方法都不會(huì)拋異常。在這之后會(huì)進(jìn)入到foreach循環(huán)方法體中的remove方法中,進(jìn)行刪除元素。同上,size-1變?yōu)榱?,而modCount+1變?yōu)榱?。
第二次循環(huán):
在第二次循環(huán)的hasNext方法中,此時(shí)的cursor為1,而size也是1,兩者相等。所以hasNext方法返回false,就跳出了foreach循環(huán),不會(huì)走到隨后的next方法中,也就不會(huì)拋出異常。
2.源碼步驟
第一次
第①句調(diào)用iterator(),
調(diào)用了new Itr(),生成Itr類(lèi)(迭代器)。此時(shí)會(huì)給Itr的三個(gè)參數(shù)初始化。
此時(shí)expectedModCount == modCount == 2(因?yàn)閘ist調(diào)動(dòng)了add方法,add方法會(huì)對(duì)modCount實(shí)現(xiàn)++操作)
第②句調(diào)用下面hasNext()方法,返回下一個(gè)要訪(fǎng)問(wèn)元素的下標(biāo)cursor,因?yàn)槭堑谝淮窝h(huán),所以cursor為0,size為2 (0 != 2 true)
第③句調(diào)用next()方法,foreach循環(huán)方法體中的remove方法的if條件判斷不滿(mǎn)足,就結(jié)束了本次循環(huán)
第二次
第②句調(diào)用下面hasNext()方法,返回下一個(gè)要訪(fǎng)問(wèn)元素的下標(biāo)cursor,第二次循環(huán),所以cursor為1,
size還是為2 (1 != 2 true)
第③句調(diào)用next()方法,正常取值,取到第一個(gè)元素"2";
第④句調(diào)用remove()方法,成功給list刪除元素。注意,在調(diào)用remove方法的時(shí)候,有modCount++。所有此時(shí),modCount3,expectedModCount2,size1
第三次
第②句調(diào)用下面hasNext()方法,返回下一個(gè)要訪(fǎng)問(wèn)元素的下標(biāo)cursor,第二次循環(huán),所以cursor為2,size為1
第③句調(diào)用next()方法,注意,在next()方法中第一句話(huà)就是調(diào)用checkForComodification();由于modCount(3) != expectedModCount(2),所以就拋了異常。
3.為啥都是底層都是iterator,為啥foreach會(huì)報(bào)錯(cuò)
當(dāng)循環(huán)結(jié)束的時(shí)候,while (iterator.hasNext()) 會(huì)檢查是否有下個(gè)元素存在,在remove刪除2完成后,下次進(jìn)入cursor還是1,size也是1.
foreach的話(huà),刪除remove2之后,下次進(jìn)入cursor是2,size是1,所以返回false,要走next方法,然后,進(jìn)行檢查,modCount=3,而expectedModCount=2
三、查看源碼方法
如果查看iterator下的ArrayList
remove也是如此
到此這篇關(guān)于Java ArrayList遍歷foreach與iterator時(shí)remove的區(qū)別的文章就介紹到這了,更多相關(guān)Java ArrayList遍歷內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java8 ArrayList之forEach的使用
- Java中ArrayList在foreach里remove的問(wèn)題詳析
- Java?報(bào)錯(cuò)?java.util.ConcurrentModificationException:?null?的原因及解決方案
- Java ConcurrentModificationException異常解決案例詳解
- 詳解Java刪除Map中元素java.util.ConcurrentModificationException”異常解決
- ArrayList?foreach循環(huán)增添刪除導(dǎo)致ConcurrentModificationException解決分析
相關(guān)文章
SpringBoot環(huán)境下junit單元測(cè)試速度優(yōu)化方式
這篇文章主要介紹了SpringBoot環(huán)境下junit單元測(cè)試速度優(yōu)化方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09在MyBatis中實(shí)現(xiàn)一對(duì)多查詢(xún)和多對(duì)一查詢(xún)的方式詳解(各兩種方式)
今天通過(guò)兩種方法分別給大家介紹在MyBatis中實(shí)現(xiàn)一對(duì)多查詢(xún)和多對(duì)一查詢(xún)的方式,每種方式通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-01-01Java數(shù)據(jù)結(jié)構(gòu)之棧的詳解
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之棧簡(jiǎn)單操作的相關(guān)資料,需要的朋友可以參考下,希望能夠給你帶來(lái)幫助2021-09-09Springboot mybatis plus druid多數(shù)據(jù)源解決方案 dynamic-datasource的使用詳
這篇文章主要介紹了Springboot mybatis plus druid多數(shù)據(jù)源解決方案 dynamic-datasource的使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11SpringBoot actuator 健康檢查不通過(guò)的解決方案
這篇文章主要介紹了SpringBoot actuator 健康檢查不通過(guò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07MyBatis中多對(duì)多關(guān)系的映射和查詢(xún)
本文主要介紹了MyBatis中多對(duì)多關(guān)系的映射和查詢(xún)的相關(guān)知識(shí)。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02