在列表迭代期间从java.util.List中删除元素时抛出ConcurrentModificationException?

hgu*_*ser 60 java list concurrentmodification

@Test
public void testListCur(){
    List<String> li=new ArrayList<String>();
    for(int i=0;i<10;i++){
        li.add("str"+i);
    }

    for(String st:li){
        if(st.equalsIgnoreCase("str3"))
            li.remove("str3");
    }
    System.out.println(li);
}
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,我将抛出一个ConcurrentModificationException.

看起来当我从列表中删除指定的元素时,列表不知道它的大小是否已被更改.

我想知道这是集合和删除元素的常见问题吗?

Pau*_*ing 89

我相信这是Iterator.remove()方法背后的目的,以便能够在迭代时从集合中删除元素.

例如:

Iterator<String> iter = li.iterator();
while(iter.hasNext()){
    if(iter.next().equalsIgnoreCase("str3"))
        iter.remove();
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,你将不能使用for-each循环,你必须切换到使用`Iterator`. (7认同)
  • 不幸的是,在foreach循环中,没有对底层迭代器的访问,因此隐藏了`iterator.remove()`. (5认同)

小智 24

在没有Iterator的情况下从Java中删除它的Java 8方法是:

li.removeIf(<predicate>)
Run Code Online (Sandbox Code Playgroud)

List<String> li = new ArrayList<String>();
// ...
li.removeIf(st -> !st.equalsIgnoreCase("str3"));
Run Code Online (Sandbox Code Playgroud)


Ser*_*hiy 18

请注意,此异常并不总是表示某个对象已被另一个线程同时修改.如果单个线程发出违反对象合同的一系列方法调用,则该对象可能会抛出此异常.例如,如果一个线程在使用失败快速迭代器迭代集合时直接修改了一个集合,那么迭代器将会抛出此异常

摘自http://download.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html


hvg*_*des 6

是的人遇到它 - 问题是你不能修改列表迭代它.我过去使用了两种替代品:

  1. 您可以跟踪要删除的项目的索引,然后在完成迭代后删除它们.
  2. 或者,您可以在迭代时将所有要保留的列表复制到新列表中,然后在完成后放弃旧列表.

这些选项假设您必须遍历列表以查找要删除的元素 - 在列表元素是具有您可能测试的属性的复杂对象的情况下非常有用.

在您的特定情况下,您甚至不需要迭代,因为您可以使用removeAll.在这里查看API .还有一些漂亮的方法,比如retainAll,可以丢弃参数中没有的所有内容.只要列表中的对象正确实现equals和hashcode,就可以使用remove/retain-like方法.如果您不能依赖equals/hashcode来识别应用程序中实例之间的相等性,那么您必须自己进行删除....


Tar*_*nyk 5

试试这个(Java 8):

list.removeIf(condition);
Run Code Online (Sandbox Code Playgroud)