還是先舉個例子,你侄女對天文知識感興趣,然後你就用程式寫了太陽系九大星系(水星、金星、地球、火星、木星、土星、天王星、海王星、冥王星)的執行軌跡圖,然後拿給侄女看。然後她說錯了錯了,你的知識太舊了,多了一顆星。根據2006年8月24日國際天文聯合大會召開,在會議上經過投票表決,冥王星被降級為矮行星,太陽系目前只剩下八顆行星。所以你需要刪除一顆星。這個時候你開啟電腦開始刪除冥王星。
你從下面List中刪除一顆星。
List<String> tempList = Arrays.asList("水星","金星","地球","火星",
"木星","土星","天王星","海王星","冥王星","冥王星");
怎麼刪除List中的冥王星呢?[PS為了演示某些刪除方法不可靠,重複寫了冥王星] 。
先寫一段阿里規約:
【強制】不要再foreach迴圈裡進行元素的remove/add操作,remove元素請使用Iterator方式,如果並行的操作,需要對Iterator物件加鎖。
好了,那就讓我們來寫所有可能刪除元素的方法
1:普通的for迴圈的刪除(不可靠)。
List<String> list = new ArrayList(tempList); for (int i = 0; i < list.size(); i++) { String str = list.get(i); if ("冥王星".equals(str)) { list.remove(i); } } System.out.println(list);
執行結果如下:
[水星, 金星, 地球, 火星, 木星, 土星, 天王星, 海王星, 冥王星]
奇了怪了,沒刪除乾淨?
問題出在 list.size(),因為 list.size() 和 i 都是動態變化的,i 的值一直在累加,list.size() 一直在減少,所以 list 就會早早結束了迴圈。所以這種方式雖然不會報錯,但存在隱患,並且不容易被察覺,不建議使用。
2:普通的for迴圈提取變數進行刪除(這個更不可靠,會報錯)。
List<String> list = new ArrayList(tempList); int size = list.size(); for (int i = 0; i < size; i++) { String result = list.get(i); if ("冥王星".equals(result)) { list.remove(i); } } System.out.println(list);
結果如下:
這更不對了,一下子搞出個下標越界。
因為 size 變數是固定的,但 list 的實際大小是不斷減小的,而 i 的大小是不斷累加的,一旦 i >= list 的實際大小肯定就異常了。
3:普通的for迴圈倒敘刪除(這個用法可以,但也不推薦,倒敘看著很彆扭,個人意見)。
for (int i = list.size() - 1; i > 0; i--) { String result = list.get(i); if ("冥王星".equals(result)) { list.remove(i); } } System.out.println(list);
執行結果如下:
[水星, 金星, 地球, 火星, 木星, 土星, 天王星, 海王星]
4:使用增強的for迴圈刪除(會丟擲異常,不推薦,注意我這次為了演示效果,把行星的順序換一下),不少開發者喜歡用這種方式。
List<String> tempList = Arrays.asList("水星","金星","地球","火星", "冥王星","土星","天王星","海王星","冥王星","木星"); List<String> list = new ArrayList(tempList); for (String item : list) { if ("冥王星".equals(item)) { list.remove(item); } } System.out.println(list);
結果如下:
奇了怪了,又拋異常了。不過這次的異常和上面的下標異常不太一樣,這次是:
java.util.ConcurrentModificationException
這個是集合操作中很常見的異常之一,即並行修改異常!
增強的 for迴圈,其內部是呼叫的 Iterator 的方法,取下個元素的時候都會去判斷要修改的數量(modCount)和期待修改的數量(expectedModCount)是否一致,不一致則會報錯,而 ArrayList 中的 remove 方法並沒有同步期待修改的數量(expectedModCount)值,所以會拋異常了。
Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ String item = iterator.next() ; if ("冥王星".equals(item)){ iterator.remove(); } } System.out.println(list);
結果如下,十分完美和正確:
[水星, 金星, 地球, 火星, 土星, 天王星, 海王星, 木星]
這是因為迭代器中的 remove 方法將期待修改的數量(expectedModCount)值進行了同步。
6:迭代器迴圈集合刪除(這個可能很多開發者也會這樣寫,也可能會丟擲異常的)。
Iterator<String> iterator = list.iterator(); while (iterator.hasNext()){ String item = iterator.next() ; if ("冥王星".equals(item)){ list.remove(item); } } System.out.println(list);
結果如下:
7:Stream filter 過濾(十分推薦,當然使用這個刪除需要JDK的環境在8及其8以上的版本)。
list = list.stream().filter(item -> !"冥王星".equals(item)).
collect(Collectors.toList());
System.out.println(list);
結果如下,十分完美和正確:
這個方法利用了 Stream 的篩選功能,快速過濾所需要的元素,雖然不是進行集合刪除,但達到了同樣的目的,這種方法要更簡潔
看了上面的幾個例子,相信你熟悉了List刪除元素的用法了,希望你看了上面的例子,開發的時候不會再犯錯了。