在Java中循環遍歷List有三種方式:for循環、增強for循環(也就是常說的foreach循環)和iterator遍歷。下面就這三種方式嘗試移除List中的元素,看看是否存在問題。
List<String> list = new ArrayList<>(); list.add("yanggb"); list.add("yanggb1"); list.add("yanggb2"); list.add("yanggb2"); list.add("yanggb3");
1.for循環遍歷List
for (int i = 0; i < list.size(); i++) { if ("yanggb2".equals(list.get(i))) { list.remove(i); } }
這種方式的問題在於,刪除某個元素之后,因為List的大小發生了變化,List中元素的下標索引也在變化,所以會導致你在遍歷的時候漏掉某些元素。比如當你刪除第1個元素后,繼續根據索引訪問第2個元素時,因為刪除的關系后面的元素都往前移動了一位,所以實際訪問的是原本的第3個元素。因為可能會導致漏刪元素的問題,這種方式只能用於刪除特定的一個元素的場景,但不適合循環刪除多個元素的場景中使用。
具體地說,因為集合的大小是動態變化的,當你刪除第一個要刪除的元素之后,元素中的序號又重新排列,原來第二個要刪除的元素在List中的下標往前移動了一位,如果這個第二個要刪除的元素排在第一個要刪除的元素之后,那么當循環的下標往后推一位之后,這個第二個要刪除的元素永遠不會被刪除,因為循環不到這個元素了。。。究其原因是因為你要刪除的元素往前面移動了,而你的i保存的值依舊往后走,所以如果讓i不往后走,往前走一個,即可刪除本來排在第二個位置的元素現在排在了第一個位置上的元素,這個就是解決這個問題的一個方法:
for (int i = 0; i < list.size(); i++) { list.remove(i); i--; // 動態前移循環中List的下標 }
另外的一個解決方法是倒序進行循環,這樣的話刪除元素就不會影響循環中的下標與List中元素原本下標的對應關系,也就不會出現元素刪除漏了的問題。
for (int i = list.size() - 1; i >= 0; i--) { list.remove(i); }
2.增強for循環遍歷List
for (String yanggb : list) { if ("yanggb2".equals(yanggb)) { list.remove(yanggb); } }
這種方式的問題在於,刪除元素后繼續循環會報錯誤信息ConcurrentModificationException,因為元素在使用的時候發生了並發的修改,導致異常拋出。但是如果在刪除一個元素之后馬上使用break跳出,則不會觸發報錯,因此這種方式只適用於只刪除一個元素的場景。通過查看源代碼可以發現,報錯的原因在於在checkForComodification()方法中如果modCount變量不等於expectedModCount變量,就會拋出ConcurrentModificationException異常。
關於ConcurrentModificationException的具體原因及解決參考:https://www.cnblogs.com/dolphin0520/p/3933551.html#undefined
3.Iterator遍歷
Iterator<String> it = list.iterator(); while (it.hasNext()){ String yanggb = it.next(); if ("yanggb2".equals(yanggb)) { it.remove(); } }
這種方式可以正常地進行循環及刪除。但要注意的一點是,這里使用的是Iterator的remove()方法,如果用List的remove()方法同樣會報上面提到的ConcurrentModificationException錯誤。
"人生好像就是那么的變化多端,你從來都沒法肯定一件事情以后會不會出現什么出人意料的轉折。"