我正在阅读这个“Freuqent Java concurrency problems”问题,并且在回答java.util.ConcurrentModificationException的答案时感到困惑。
我对答案的理解是,这可能发生在单线程程序中。 如何或什么条件导致以下代码抛出异常?
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }
答案 0 :(得分:14)
此代码段总是抛出ConcurrentModificationException
。
规则如下:使用迭代器迭代时,您不能修改(添加或删除列表中的元素)(当您使用for-each循环时会发生这种情况)。
但是请注意,您可以使用Iterator.remove
或ListIterator.add
来通过迭代器修改列表(因为它知道修改,并且可以将其考虑在内)。
来自文档:
此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出一个ConcurrentModificationException。
concurrent 这个词指的是你在遍历期间修改列表。
答案 1 :(得分:2)
您在循环播放列表时正在更改列表。
此处ConcurrentModificationException
与线程无关。
警告!以下示例显示了在更改集合时如何使用集合可能会有危险。这不是OP的情况(通过迭代器和更改循环)
如果您使用带有这样的计数器的老式循环,我认为更容易想象它有什么问题:
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (int i = 0; i < list.size(); i++) {
list.remove(i); //removes element at given index
}
现在,第一次i
为0,第0个元素被删除。第二次i
为1,所以现在删除第一个元素。但是,在第一次移除之前,现在是第一个,曾经是第二个。那么,曾经是第一,现在是第0,永远不会被删除。
答案 2 :(得分:2)
因为您要从列表中删除并同时使用迭代器对其进行迭代。
使用迭代器查看等效代码。
import java.lang.*;
import java.util.*;
class Test{
public static void main(String[] argv){
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
Iterator<String> itr=list.iterator();
while(itr.hasNext()){
String a=itr.next();
list.remove(a);
}
}
}
正确的代码是
import java.lang.*;
import java.util.*;
class Test{
public static void main(String[] argv){
List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
Iterator<String> itr=list.iterator();
while(itr.hasNext()){
itr.remove();
}
}
}