关于
在这次实验中遇到了一个在迭代器中remove时候的bug,注意到老师上课讲过,今天自己用代码测试了一下,果然有问题。
问题描述
如果直接利用foreach迭代,在迭代过程中,如果在迭代的集合上进行更改,例如remove,add等方法,编译时就会报错
例如,写一个ArrayList的代码如下:
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(4);
list.add(6);
list.add(8);
list.add(9);
list.add(10);
for (Integer integer : list) {
//这段代码错误. 迭代器移除会报错.
if (integer % 2 == 0) {
list.remove(integer);
}
}
System.out.println(list);
编译时,会报如下错误:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at testForIterator.testForArray.main(testForArray.java:***)
我尝试了一下利用存储下标的方式进行更改,先将要移除的元素下标存起来,然后再移除:
List<Integer> list = new ArrayList<>();
List<Integer> indexArray = new ArrayList<>();
int index = 0;
list.add(3);
list.add(4);
list.add(6);
list.add(8);
list.add(9);
list.add(10);
/*
* 输出[4,6,8,9,10]与预期不同.
* */
for (Integer integer : list) {
if (integer %2 == 0) {
indexArray.add(index);
}
index++;
}
for(Integer i : indexArray) {
list.remove(i);
}
System.out.println(list);
然而再移除时,依然犯了上面的错误,当然也可以一个一个移除,不过如果数据量相当大,那样效率太低,代码也会相当糟糕,因此不建议使用这种方法。
解决方法
最好的解决方法就是使用迭代器自己的remove方法,代码如下所示:
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(4);
list.add(6);
list.add(8);
list.add(9);
list.add(10);
/*
* 使用迭代器本身的remove方法.
* */
Iterator<Integer> iter = list.iterator();
while (iter.hasNext()) {
int i = iter.next();
if (i % 2 == 0) {
iter.remove();
}
}
System.out.println(list);
为什么呢?
在foreach循环中,编译器会使.next()方法在删除元素之后被调用,因此就会抛出一个ConcurrentModificationException异常。
结论
在java的集合列表中,迭代时需要增加或删除元素时,最安全的方式便是使用Iterator方法。