从ArrayList中删除元素时出现ConcurrentModificationException

时间:2014-04-19 13:22:02

标签: java collections

当我运行以下代码时,Java正在抛出ConcurrentModificationException。知道为什么会这样吗?

ArrayList<String> list1 = new ArrayList<String>();
list1.add("Hello");
list1.add("World");
list1.add("Good Evening");

for (String s : list1){
        list1.remove(2);
    System.out.println(s);
}

4 个答案:

答案 0 :(得分:0)

如果您查看ConcurrentModificationException的文档,您会发现

  

检测到并发的方法可能抛出此异常   在不允许进行此类修改时修改对象。

     

例如,一个线程通常不允许修改   一个集合,而另一个线程迭代它

     

...

     

请注意,此异常并不总是表示对象具有   由另一个线程同时修改。如果是单线程   发出一系列违反合同的方法调用   一个对象,该对象可能抛出此异常。 例如,如果是   线程在迭代时直接修改集合   使用失败快速迭代器进行集合,迭代器将抛出此异常   例外

关于此异常的重要一点是,我们无法保证它将始终按照文档

中的说明抛出
  

请注意,通常情况下无法保证快速失败的行为   说话,在场的情况下不可能做出任何硬性保证   不同步的并发修改。 失败操作抛出   尽最大努力ConcurrentModificationException

同样来自ArrayList文档

  

此类iteratorlistIterator返回的迭代器   方法是 失败快速:如果列表在结构上被修改了   创建迭代器之后的时间,除了通过之外的任何方式   迭代器自己删除或添加方法,迭代器会抛出一个   ConcurrentModificationException

(强调我的)

所以你不能操纵Collection的内容(在你的情况下是List),同时通过增强的for循环遍历它,因为你没有通过iterator来做 - 每个都在内部使用。

要解决它,只需获得自己的Iterator并在循环中使用它。要从集合中删除元素,请使用此示例中的remove

Iterator<String> it = list1.iterator();
int i=0;
while(it.hasNext()){
    String s = it.next();
    i++;
    if (i==2){
        it.remove();
        System.out.println("removed: "+ s);
    }
}

答案 1 :(得分:0)

在迭代项目时,您无法删除该项目。如果要在迭代时也删除项目,请使用Iterator

但您要删除基于索引的项目,然后只需在循环外移动就行可以解决您的问题。

 list1.remove(2);

答案 2 :(得分:0)

形成您可以阅读的doc

  

检测到并发的方法可能抛出此异常   当不允许这种修改时修改对象。   例如,一个线程通常不允许修改   一个集合,而另一个线程正在迭代它。一般来说,   在这些情况下,迭代的结果是不确定的。   一些迭代器实现(包括所有通用的实现)   由JRE提供的目的集合实现可以选择   如果检测到此行为,则抛出此异常。那个迭代器   这被称为故障快速迭代器,因为它们很快就会失败   干净利落,而不是冒着任意的,非确定性的行为冒险   未来不确定的时间。

此外,假设您可以在每次迭代时删除第2项。您将最终进入索引超出范围的异常:

  • 在第一次迭代时,您删除第2项("Good evening"),列表大小变为1(项目0 "hello"和项目1 "World"
  • 在下一次迭代中,您将删除列表中实际不存在的第2项。你的列表的大小确实是2,但是计数器从0开始,因此你最终删除了不存在的东西:这是非确定性行为的一个例子。

答案 3 :(得分:0)

在修改基础列表后,您无法遍历列表。如果您这样做,它会给您ConcurrentModificationException

要解决此问题,请使用java.util.ListIterator进行列表迭代。

    ListIterator<String> it = list1.listIterator();
    for (String s : list1) {
        if (it.hasNext()) {
            String item = it.next();
            System.out.println(item);
        }
        }