被問到List 如何一邊遍歷一邊刪除,該怎麼回?教你 3 種方法

這是最近面試時被問到的1道面試題,本篇文章對此問題進行總結分享。java

文章來源於微信公衆號丨程序員吳師兄git

1. 新手常犯的錯誤

可能不少新手(包括當年的我,哈哈)第一時間想到的寫法是下面這樣的:程序員

publicstaticvoidmain(String[]args){List<String>platformList=newArrayList<>();platformList.add("博客園");platformList.add("CSDN");platformList.add("掘金");for(Stringplatform:platformList){if(platform.equals("博客園")){platformList.remove(platform);}}System.out.println(platformList);}

 

而後滿懷信心地去運行,結果居然拋java.util.ConcurrentModificationException異常了,翻譯成中文就是:併發修改異常。面試

是否是很懵,心想這是爲何呢?算法

讓咱們首先看下上面這段代碼生成的字節碼,以下所示:編程

由此能夠看出,foreach循環在實際執行時,其實使用的是Iterator,使用的核心方法是hasnext()和next()。數組

而後再來看下ArrayList類的Iterator是如何實現的呢?微信

能夠看出,調用next()方法獲取下一個元素時,第一行代碼就是調用了checkForComodification();,而該方法的核心邏輯就是比較modCount和expectedModCount這2個變量的值。數據結構

在上面的例子中,剛開始modCount和expectedModCount的值都爲3,因此第1次獲取元素"博客園"是沒問題的,可是當執行完下面這行代碼時:併發

platformList.remove(platform);

modCount的值就被修改爲了4。

因此在第2次獲取元素時,modCount和expectedModCount的值就不相等了,因此拋出了java.util.ConcurrentModificationException異常。

既然不能使用foreach來實現,那麼咱們該如何實現呢?

主要有如下3種方法:

使用Iterator的remove()方法

使用for循環正序遍歷

使用for循環倒序遍歷

接下來一一講解。

2. 使用Iterator的remove()方法

使用Iterator的remove()方法的實現方式以下所示:

publicstaticvoidmain(String[]args){List<String>platformList=newArrayList<>();platformList.add("博客園");platformList.add("CSDN");platformList.add("掘金");Iterator<String>iterator=platformList.iterator();while(iterator.hasNext()){Stringplatform=iterator.next();if(platform.equals("博客園")){iterator.remove();}}System.out.println(platformList);}

 

輸出結果爲:

[CSDN,掘金]

爲何使用iterator.remove();就能夠呢?讓咱們看下它的源碼:

能夠看出,每次刪除一個元素,都會將modCount的值從新賦值給expectedModCount,這樣2個變量就相等了,不會觸發java.util.ConcurrentModificationException異常。更多面試題,歡迎關注公衆號 Java面試題精選

3. 使用for循環正序遍歷

使用for循環正序遍歷的實現方式以下所示:

public static void main(String[] args) {    List<String> platformList = new ArrayList<>();    platformList.add("博客園");    platformList.add("CSDN");    platformList.add("掘金");      for (int i = 0; i < platformList.size(); i++) {        String item = platformList.get(i);          if (item.equals("博客園")) {            platformList.remove(i);            i = i - 1;        }    }      System.out.println(platformList); }

 

這種實現方式比較好理解,就是經過數組的下標來刪除,不過有個注意事項就是刪除元素後,要修正下下標的值:

i=i-1;

爲何要修正下標的值呢?由於剛開始元素的下標是這樣的:

第1次循環將元素"博客園"刪除後,元素的下標變成了下面這樣:

第2次循環時i的值爲1,也就是取到了元素」掘金「,這樣就致使元素"CSDN"被跳過檢查了,因此刪除完元素後,咱們要修正下下標,這也是上面代碼中i = i – 1;的用途。更多面試問題能夠關注微信訂閱號碼將筆記回覆面試獲取

4. 使用for循環倒序遍歷

使用for循環倒序遍歷的實現方式以下所示:

publicstaticvoidmain(String[]args){List<String>platformList=newArrayList<>();platformList.add("博客園");platformList.add("CSDN");platformList.add("掘金");for(inti=platformList.size()-1;i>=0;i--){Stringitem=platformList.get(i);if(item.equals("掘金")){platformList.remove(i);}}System.out.println(platformList);}

 

這種實現方式和使用for循環正序遍歷相似,不過不用再修正下標,由於剛開始元素的下標是這樣的:

第1次循環將元素"掘金"刪除後,元素的下標變成了下面這樣:

第2次循環時i的值爲1,也就是取到了元素」CSDN「,不會致使跳過元素,因此不須要修正下標。

好了,這篇文章就到這裏,感謝你們的閱讀,喜歡的話給個三連吧~

做爲一名編程學習者,若是你想更好地提高你的編程能力,好好學習C/C++編程知識以及數據結構,之後努力成爲高薪算法/軟件開發工程師的話!

C語言C++編程學習交流圈子,QQ羣464501141點擊進入】微信公衆號:C語言編程學習基地

分享(源碼、項目實戰視頻、項目筆記,基礎入門教程)

歡迎轉行和學習編程的夥伴,利用更多的資料學習成長比本身琢磨更快哦!

編程學習書籍:

編程學習視頻:

 

相關文章
相關標籤/搜索