为什么说JAVA 集合中 使用for循环删除当前集合中的元素异常
先看一下异常
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at com.ge.yulaifo.thread.Test.main(Test.java:15)
首先,说一下应用场景:
在写程序的时候,我们经常会使用for循环来遍历集合,有时候会有这样的需求,使用一个循环来遍历集合,当遍历到某个元素时,发现这个元素不应该存在当前的循环中,或者说这个元素在当前的集合中已经没意义了,为了省去内存要把这个对象销毁,并且同时把这个元素从集合中移除,如果你使用的是for循环对自身进行遍历并删除某个元素的操作,那恭喜你,踩坑了!
下面使用两种循环方式来说明一下为什么踩坑!
初始化一个ArrayList集合
ArrayList<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
第一个坑
利用增强for循环遍历
for (String strValue : list) {
System.out.println(strValue);
if ("a".equals(strValue)) {
list.remove(strValue);
}
}
当“a”元素满足删除删除条件时,直接进行remove操作:
发生以下错误:
Exception in thread "main" a
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:907)
at java.util.ArrayList$Itr.next(ArrayList.java:857)
因为元素在使用的时候发生了并发的修改,导致异常抛出。
第二个坑
利用集合的长度遍历
for (int i = 0; i < list.size(); i ++) {
String strValue = list.get(i);
System.out.println(strValue);
if ("a".equals(strValue)) {
list.remove(strValue);
}
}
同样,当元素满足条件时,进行remove操作,输出结果:
a
c
貌似感觉良好,没报错,但是发现把第二个元素落下了,没有遍历。
原因是当i=0时,第0个元素“a”刚好满足删除条件,那么删掉第0个元素后,集合的长度也随着发生了变化,第0个元素就变成了“b”,第1个元素变成了“c”,长度变成了2,当for循环继续向下循环时,i的值是1,那么就直接忽略了“b”元素,所以这样遍历删除也是行不通的。
到底该怎么搞?
推荐使用迭代器进行遍历删除元素:
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String strValue = iterator.next();
System.out.println(strValue);
if ("a".equals(strValue)) {
iterator.remove();//使用迭代器的删除进行删除操作
//list.remove(strValue);//如果使用集合自带的remove方法同样会遇到上述的错误
}
}
真香!