从ArrayList中删除元素时出现ConcurrentModificationException
当我运行以下代码时,Java正在抛出ConcurrentModificationException。 Anyidea为什么会这样?
ArrayList list1 = new ArrayList(); list1.add("Hello"); list1.add("World"); list1.add("Good Evening"); for (String s : list1){ list1.remove(2); System.out.println(s); }
如果你看一下ConcurrentModificationException的文档,你会发现它
当不允许这样的修改时,检测到对象的并发修改的方法可能抛出此exception。
例如, 一个线程通常不允许修改Collection,而另一个线程正在迭代它
…
请注意,此exception并不总是表示某个对象已被另一个线程同时修改。 如果单个线程发出违反对象合同的一系列方法调用,则该对象可能会抛出此exception。 例如,如果线程在使用失败快速迭代器迭代集合时直接修改集合,则迭代器将抛出此exception 。
关于此exception的重要一点是,我们无法保证它将始终按照文档中的说明抛出
请注意,无法保证快速失败的行为,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。 失败快速操作会尽最大努力抛出
ConcurrentModificationException
。
也来自ArrayList文档
这个类的
iterator
和listIterator
方法返回的iterator
是快速失败的 :如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出ConcurrentModificationException
。
(强调我的)
所以你不能操纵Collection的内容(在你的情况下是List),同时通过增强的for循环遍历它,因为你没有通过迭代器来做 – 每个都在内部使用。
要解决它,只需获得自己的Iterator
并在循环中使用它。 要从集合中删除元素,请使用此示例中的remove
Iterator it = list1.iterator(); int i=0; while(it.hasNext()){ String s = it.next(); i++; if (i==2){ it.remove(); System.out.println("removed: "+ s); } }
迭代时,您无法删除项目。 如果要在迭代时也删除项目,请使用Iterator
。
但是你要删除一个基于索引的项目,然后只需在循环外移动就可以解决你的问题。
list1.remove(2);
形成你可以阅读的文档
当不允许这样的修改时,检测到对象的并发修改的方法可能抛出此exception。 例如,一个线程通常不允许修改Collection,而另一个线程正在迭代它。 通常,在这些情况下,迭代的结果是不确定的。 如果检测到此行为,某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此exception。 执行此操作的迭代器称为故障快速迭代器,因为它们快速且干净地失败,而不是在未来的未确定时间冒着任意的,非确定性行为的风险。
此外,假设您可以在每次迭代时删除第2项。 您将最终进入索引超出范围的exception:
- 在第一次迭代中,您删除项目#2(
"Good evening"
),列表大小变为1(项目0"hello"
和项目1"World"
) - 在下一次迭代中,您将删除列表中实际不存在的第2项。 你的列表的大小确实是2,但是计数器从0开始,因此你最终删除了不存在的东西:这是非确定性行为的一个例子。
修改基础列表后,您无法遍历列表。如果您这样做,它会给您ConcurrentModificationException
要解决此问题,请使用java.util.ListIterator
进行列表的迭代。
ListIterator it = list1.listIterator(); for (String s : list1) { if (it.hasNext()) { String item = it.next(); System.out.println(item); } }