Java遍歷List並刪除某些元素
在阿里的Java編程規約中有一條:【強制】不要在foreach循環里進行元素的remove/add操作。remove元素請使用Iterator方式,如果並發操作,需要對Iterator對象加鎖。
這里不禁要問為什么?
首先來試一下,遍歷List時刪除元素究竟行不行:
public class IteratorTest {
public static void singleThreadRemove1(){
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for (String l : list){
if ("1".equals(l)){
list.remove(l);
}
}
System.out.println(list);
}
public static void main(String[] args){
singleThreadRemove1();
}
}
運行結果:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
at java.util.ArrayList$Itr.next(ArrayList.java:859)
at blog.IteratorTest.singleThreadRemove1(IteratorTest.java:19)
at blog.IteratorTest.main(IteratorTest.java:28)
Process finished with exit code 1
定位報錯日志可以發現,遍歷每個元素都會調用next()方法,next()方法首先有一個校驗:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
這里modCount是指list實際修改的次數,expectedModCount是預計修改的次數,調用List的remove()方法只會增加modCount的值,而不會增加expectedModCount,也就是說這是Java在讓我們避免在for循環中刪除list的元素。
要想知道為什么要避免這種操作很簡單,將上面程序中條件改為“當元素值等於‘2’時刪除元素”,此時會發現程序可以正常運行!當list遍歷完第二個元素時,這時准備進入第三個元素,然而list的元素數量已經減少,第三個索引位置上沒有元素,循環結束。這是多么荒唐的事啊,循環遍歷元素,明明有一個元素沒有走到,循環卻正常結束。