关于java:ArrayList的ConcurrentModificationException

ConcurrentModificationException for ArrayList

本问题已经有最佳答案,请猛点这里访问。

我有以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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("]"),"
         "
);
        }
    return str.toString();
}

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


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

1
2
3
4
5
for (DrugStrength aDrugStrength : aDrugStrengthList) {
    if (!aDrugStrength.isValidDrugDescription()) {
        aDrugStrengthList.remove(aDrugStrength);
    }
}

用:

1
2
3
4
5
6
for (Iterator<DrugStrength> it = aDrugStrengthList.iterator(); it.hasNext(); ) {
    DrugStrength aDrugStrength = it.next();
    if (!aDrugStrength.isValidDrugDescription()) {
        it.remove();
    }
}


像其他答案所说的那样,您不能从正在迭代的集合中删除项目。您可以通过显式地使用Iterator并删除其中的项目来绕过这个问题。

1
2
3
4
5
6
7
Iterator<Item> iter = list.iterator();
while(iter.hasNext()) {
  Item blah = iter.next();
  if(...) {
    iter.remove(); // Removes the 'current' item
  }
}


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

1
2
3
4
5
6
int size = list.size();
for (int i = size - 1; i >= 0; i--) {
    if(remove){
        list.remove(i);
    }
}

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


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

尝试java.util.concurrent.copyonWriteArrayList.class


在循环中迭代时,您正在尝试在remove()操作中更改列表值。这将导致同时修改例外。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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("]"),"
         "
);
    }
    return str.toString();
}


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

查看此日志中的Concurrenthashmap

http://www.journaldev.com/122/hashmap vs concurrenthashmap-%e2%80%93示例和探索迭代器