为什么从列表中删除元素会抛出ConcurrentModificationException?

时间:2013-04-19 23:53:37

标签: java exception iterator

当我运行以下代码时,我的程序抛出ConcurrentModificationException。通过一些研究,我发现在迭代器循环中无法添加或删除列表中的元素。我现在该怎么做才能删除List<Bean>中的元素?

for (Iterator<Entry<String, List<Bean>>> iterator = dataMap.entrySet().iterator(); iterator.hasNext();) {
    Entry<String, List<Bean>> entry = (Entry<String, List<Bean>>)iterator.next();
    List<Bean> dateWiseValues = (List<Bean>) entry.getValue();
    int j = 0;
    for (Bean statBean : dateWiseValues) {
        for (int i = 0; i < commonElements.size(); i++) {
            if(statBean.getDate().equalsIgnoreCase(commonElements.get(i))) {
                //remove the bean
                entry.getValue().remove(j);
            }
        }
        j++;
    }
} 

2 个答案:

答案 0 :(得分:5)

不要在dateWiseValues上使用基于范围的 for 循环,而是明确使用Iterator,以便您可以改为调用Iterator#remove()

for (final Iterator<? extends Bean> it = dateWiseValues.iterator();
     it.hasNext();) {
  final Bean statBean = it.next();
  for (int i = 0, last = commonElements.size(); i != last; ++i)
    if (statBean.getDate().equalsIgnoreCase(commonElements.get(i)))                
      it.remove();
}

通常,只要通过集合的迭代器之一进行迭代,就可以安全地从迭代中删除元素和底层集合。


虽然我们看不到dateWiseValues的具体类型,但我们知道它是List的子类型。实现List的两种常见具体类型是ArrayListLinkedList。每个类的散文级别文档包含以下警告:

  

此类的iteratorlistIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过{{1自己的Iteratorremove方法,迭代器将抛出add。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒着任意的,非确定性行为的风险。

请注意,它警告您必须在迭代期间使用ConcurrentModificationException进行变异,否则下次使用相同或任何其他迭代器遍历同一基础列表时,您将面临抛出Iterator#remove()

答案 1 :(得分:2)

当您使用增强的for循环时,它会在幕后隐式使用Iterator。这是Iterator抛出ConcurrentModificationException,而不是您在外部iterator循环中定义的显式迭代器for。除非您调用Iterator#remove(),这会删除当前列表项并避开Iterator,否则您无法在ConcurrentModificationException迭代时从列表中删除。

您有两个选择:

  • 重写增强型for循环以明确使用while循环和Iterator,然后 如果要删除项目,请致电remove()
  • 创建要删除的List项。当你确定你想要的时候 删除该项目,add将其移至要删除的项目列表。然后, 完成迭代后,请在原始列表中调用removeAll以删除您要删除的所有项目。