迭代列表(ConcurrentModificationException)

时间:2011-05-27 15:29:39

标签: java iteration

以下代码抛出ConcurrentModificationException:

for (String word : choices) {
         List<String> choicesCopy = choices;
         chosen.add(word);
         choicesCopy.remove(word);
         subsets(choicesCopy, chosen, alreadyPrinted);
}

发生了什么事?原始列表(选项)根本没有修改。

6 个答案:

答案 0 :(得分:8)

您在此处制作了参考副本而非对象副本

List<String> choicesCopy = choices;

所以很明显你要修改同一个列表,你必然得到ConcurrentModificationException

使用Collections.copy()正确制作列表副本。

修改 如下所示,您还可以使用构造函数进行复制。

答案 1 :(得分:1)

原因是因为你无法修改foreach循环中的任何内容。尝试使用for循环。或者您已获取列表的所有内容,并将它们一次添加到另一个列表中。因为它是通过引用完成的

编辑:您需要制作列表的深层副本并从该副本中删除。然后,您可以指定原始列表的引用以指向具有修改的新引用。即使它被另一个变量引用,也无法从当前正在迭代的列表中删除。

答案 2 :(得分:1)

更改代码如下:

for (Iterator<String> it = choices.iterator(); it.hasnext();) {
     String word = it.next();
     chosen.add(word);
     it.remove();
     subsets(choicesCopy, chosen, alreadyPrinted);
}

说明:foreach循环在内部使用迭代器,但不要将其暴露给用户。因此,如果你想删除项目,你必须模拟foreach循环并自己保留对迭代器的引用。

在迭代时,从集合中删除数据的任何其他方法都会产生ConcurrentModificationException

答案 3 :(得分:1)

我认为通用解决方案是:

List<E> obj = Collections.synchronizedList(new ArrayList<E>());

答案 4 :(得分:0)

您需要正确复制列表,例如Collections.copy然后从副本中删除,或使用Iterator.remove,这将从基础集合中删除Object。迭代器快速失败,因此您无法在不使用迭代器的API的情况下更改基础集合。

答案 5 :(得分:0)

我怀疑被选中也应该是副本。否则选择将在循环结束时累积所有单词。即我怀疑所选择的和选择不应该有任何共同的词语。

我还怀疑集合应该是集合(没有重复的无序集合)而不是列表。

也许代码应该是。

Set<String> choices =
Set<String> chosen =
for (String word : choices) {
     Set<String> choicesCopy = new LinkedHashSet<String>(choices);
     choicesCopy.remove(word);
     Set<String> chosenCopy = new LinkedHashSet<String>(chosen);
     chosenCopy.add(word);

     subsets(choicesCopy, chosenCopy, alreadyPrinted);
}