列表上的迭代ConcurrentModificationException

问题描述

| 以下代码引发ConcurrentModificationException:
for (String word : choices) {
         List<String> choicescopy = choices;
         chosen.add(word);
         choicescopy.remove(word);
         subsets(choicescopy,chosen,alreadyPrinted);
}
这是怎么回事?原始列表(选择项)完全未修改。     

解决方法

        您在此处创建了参考副本而非对象副本
List<String> choicesCopy = choices;
所以很明显,您正在修改相同的列表,所以一定会得到
ConcurrentModificationException
使用Collections.copy()正确制作列表的副本。 编辑: 如下面的建议,您还可以使用构造函数进行复制。     ,        原因是因为您无法在foreach循环内修改任何内容。尝试使用for循环。或者您已获取列表的所有内容,然后一次将其添加到另一个列表中。因为它是通过引用完成的 编辑:您需要制作列表的深层副本,并从该副本中删除。然后,您可以分配原始列表的引用以指向具有修改的新列表。您不能从当前正在迭代的列表中删除,即使另一个变量正在引用该列表也是如此。     ,        像这样更改代码:
for (Iterator<String> it = choices.iterator(); it.hasnext();) {
     String word = it.next();
     chosen.add(word);
     it.remove();
     subsets(choicesCopy,chosen,alreadyPrinted);
}
说明:foreach循环在内部使用迭代器,但不要将其公开给用户。因此,如果要删除项目,则必须模拟foreach循环并自己保留对迭代器的引用。 进行迭代时,从集合中删除数据的任何其他方法将导致
ConcurrentModificationException
。     ,        我认为通用解决方案是:
List<E> obj = Collections.synchronizedList(new ArrayList<E>());
    ,        您需要正确复制列表,例如Collections.copy,然后从副本中删除,或使用Iterator.remove,它将从基础集合中删除Object。迭代器快速失败,因此如果不使用迭代器的API,就无法更改基础Collection。     ,        我怀疑选择的也应该是副本。否则,选择将在循环结束时累积所有单词。也就是说,我怀疑所选内容和选项不应有任何共同之处。 我也怀疑集合应该是集合(无重复的无序集合)而不是列表。 也许代码应该是。
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);
}