別人的好運是努力了很久才發出的光,而那些迎着光努力奔跑的人,總有一天也會閃閃發亮。java
可能不少新手第一時間想到的寫法是下面這樣的:面試
public static void main(String[] args) { List<String> platformList = new ArrayList<>(); platformList.add("博客園"); platformList.add("CSDN"); platformList.add("掘金"); for (String platform : platformList) { if (platform.equals("博客園")) { platformList.remove(platform); } } System.out.println(platformList); }
而後滿懷信心的去運行,結果居然拋java.util.ConcurrentModificationException異常了,翻譯成中文就是:併發修改異常。
是否是很懵,心想這是爲何呢?
讓咱們首先看下上面這段代碼生成的字節碼,以下所示:
由此能夠看出,foreach循環在實際執行時,其實使用的是Iterator,使用的核心方法是hasnext()和next()。數組
而後再來看下ArrayList類的Iterator是如何實現的呢?
在上面的例子中,剛開始modCount和expectedModCount的值都爲3,因此第1次獲取元素"博客園"是沒問題的,可是當執行完下面這行代碼時:微信
platformList.remove(platform);
modCount的值就被修改爲了4。
因此在第2次獲取元素時,modCount和expectedModCount的值就不相等了,因此拋出了java.util.ConcurrentModificationException異常。
既然不能使用foreach來實現,那麼咱們該如何實現呢?併發
主要有如下3種方法:spa
接下來一一講解。.net
使用Iterator的remove()方法的實現方式以下所示:翻譯
public static void main(String[] args) { List<String> platformList = new ArrayList<>(); platformList.add("博客園"); platformList.add("CSDN"); platformList.add("掘金"); Iterator<String> iterator = platformList.iterator(); while (iterator.hasNext()) { String platform = iterator.next(); if (platform.equals("博客園")) { iterator.remove(); } } System.out.println(platformList); }
輸出結果爲:code
[CSDN, 掘金]
爲何使用iterator.remove();就能夠呢?orm
讓咱們看下它的源碼:
能夠看出,每次刪除一個元素,都會將modCount的值從新賦值給expectedModCount,這樣2個變量就相等了,不會觸發java.util.ConcurrentModificationException異常。更多面試題,歡迎關注公衆號 Java面試題精選
使用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;的用途。更多面試問題能夠關注微信訂閱號碼匠筆記回覆面試獲取
使用for循環倒序遍歷的實現方式以下所示:
public static void main(String[] args) { List<String> platformList = new ArrayList<>(); platformList.add("博客園"); platformList.add("CSDN"); platformList.add("掘金"); for (int i = platformList.size() - 1; i >= 0; i--) { String item = platformList.get(i); if (item.equals("掘金")) { platformList.remove(i); } } System.out.println(platformList); }
這種實現方式和使用for循環正序遍歷相似,不過不用再修正下標,由於剛開始元素的下標是這樣的:
第1次循環將元素"掘金"刪除後,元素的下標變成了下面這樣:
第2次循環時i的值爲1,也就是取到了元素」CSDN「,不會致使跳過元素,因此不須要修正下標。
https://blog.csdn.net/zjwcdd/...
https://blog.csdn.net/wangjun...