Java ArrayList的ConcurrentModificationException

Java ArrayList的ConcurrentModificationException,java,collections,concurrency,Java,Collections,Concurrency,我有以下代码: private String toString(List<DrugStrength> aDrugStrengthList) { StringBuilder str = new StringBuilder(); for (DrugStrength aDrugStrength : aDrugStrengthList) { if (!aDrugStrength.isValidDrugDescription()) {

我有以下代码:

private String toString(List<DrugStrength> aDrugStrengthList) {
    StringBuilder str = new StringBuilder();
        for (DrugStrength aDrugStrength : aDrugStrengthList) {
            if (!aDrugStrength.isValidDrugDescription()) {
                aDrugStrengthList.remove(aDrugStrength);
            }
        }
        str.append(aDrugStrengthList);
        if (str.indexOf("]") != -1) {
            str.insert(str.lastIndexOf("]"), "\n          " );
        }
    return str.toString();
}

当我尝试运行它时,我得到ConcurrentModificationException,有人能解释为什么会发生这种情况吗,即使代码运行在同一个线程中?我怎样才能避免它呢?

在循环中迭代时,您试图在删除操作中更改列表值。这将导致ConcurrentModificationException

遵循下面的代码,这将实现您想要的,但不会抛出任何异常

private String toString(List aDrugStrengthList) {
        StringBuilder str = new StringBuilder();
    List removalList = new ArrayList();
    for (DrugStrength aDrugStrength : aDrugStrengthList) {
        if (!aDrugStrength.isValidDrugDescription()) {
            removalList.add(aDrugStrength);
        }
    }
    aDrugStrengthList.removeAll(removalList);
    str.append(aDrugStrengthList);
    if (str.indexOf("]") != -1) {
        str.insert(str.lastIndexOf("]"), "\n          " );
    }
    return str.toString();
}

正如其他答案所说,您不能从正在迭代的集合中删除项。您可以通过显式使用迭代器并删除其中的项来解决这个问题

Iterator<Item> iter = list.iterator();
while(iter.hasNext()) {
  Item blah = iter.next();
  if(...) {
    iter.remove(); // Removes the 'current' item
  }
}

如果使用for each循环浏览列表,则无法将其从列表中删除。您可以使用迭代器。替换:

for (DrugStrength aDrugStrength : aDrugStrengthList) {
    if (!aDrugStrength.isValidDrugDescription()) {
        aDrugStrengthList.remove(aDrugStrength);
    }
}
与:


应该有一个支持这种操作的列表接口的并发实现


尝试java.util.concurrent.CopyOnWriteArrayList.class

我喜欢循环的相反顺序,例如:

int size = list.size();
for (int i = size - 1; i >= 0; i--) {
    if(remove){
        list.remove(i);
    }
}

因为它不需要学习任何新的数据结构或类。

我们可以使用并发集合类来避免在迭代集合时出现ConcurrentModificationException,例如CopyOnWriteArrayList而不是ArrayList

查看这篇文章中的ConcurrentHashMap


HashMap也有同样的问题,通过Map接口的另一个实现修复了这个问题。我不知道关于CopyonWritearraylist的详细信息对这个异常的解释是ArrayList的迭代器是一个快速失效的迭代器;i、 e.当它检测到它的集合在同一时间被修改时,它将失败抛出异常。与不会引发并发修改异常的故障安全迭代器(例如,在集合ConcurrentHashMap和CopyonWritearraylist上)相比,java的foreach语法实际上使用迭代器,一些IDE会报告此解决方案,并建议用foreach forMyListener侦听器替换:MyListenerList@HugoGresse对但这是相反的方向。迭代器公开了对其迭代来说是安全的删除,这是foreach丢失的。
int size = list.size();
for (int i = size - 1; i >= 0; i--) {
    if(remove){
        list.remove(i);
    }
}