为什么我没有在这个例子中得到一个java.util.ConcurrentModificationException?

注意:我知道Iterator#remove()方法。

在下面的代码示例中,我不明白为什么main方法中的List.remove抛出ConcurrentModificationException ,但不在 remove方法中。

 public class RemoveListElementDemo { private static final List<Integer> integerList; static { integerList = new ArrayList<Integer>(); integerList.add(1); integerList.add(2); integerList.add(3); } public static void remove(Integer toRemove) { for(Integer integer : integerList) { if(integer.equals(toRemove)) { integerList.remove(integer); } } } public static void main(String... args) { remove(Integer.valueOf(2)); Integer toRemove = Integer.valueOf(3); for(Integer integer : integerList) { if(integer.equals(toRemove)) { integerList.remove(integer); } } } } 

原因如下:正如Javadoc所说:

这个类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在迭代器创建之后,在任何时候结构性地修改列表,除了通过迭代器自己的remove或add方法以外,迭代器将抛出一个ConcurrentModificationException异常。

这个检查是在迭代器的next()方法中完成的(就像你可以通过stacktrace所看到的那样)。 但是,只有当hasNext()传递true时,我们才会到达next()方法,这是每个方法调用以检查是否满足边界的情况。 在你的remove方法中,当hasNext()检查是否需要返回另一个元素时,它会看到它返回了两个元素,现在一个元素被移除后,列表中只包含两个元素。 所以,一切都很好,我们完成迭代。 并发修改的检查不会发生,因为这是在永远不会调用的next()方法中完成的。

接下来我们进入第二个循环。 在我们删除第二个数字后,hasNext方法将再次检查是否可以返回更多的值。 它已经返回了两个值,但是列表现在只包含一个值。 但是这里的代码是:

 public boolean hasNext() { return cursor != size(); } 

1!= 2,所以我们继续next()方法,它现在意识到有人已经搞乱了列表,并引发异常。

希望清除你的问题。

一种方法来处理它从一个Collection的副本(不是集合本身),如果适用删除的东西。 Clone原始集合,通过Constructor复制。

当这样的修改不被允许时,可以通过检测到对象的并发修改的方法抛出该异常。

对于您的具体情况,首先,我不认为final是一种方式去考虑你打算修改列表过去的声明

 private static final List<Integer> integerList; 

也考虑修改一个副本,而不是原来的列表。

 List<Integer> copy = new ArrayList<Integer>(integerList); for(Integer integer : integerList) { if(integer.equals(remove)) { copy.remove(integer); } } 

在移除项目时,forward / iterator方法不起作用。 您可以在不出错的情况下删除该元素,但是当您尝试访问已删除的项目时,将会收到运行时错误。 你不能使用迭代器,因为就像pushy所显示的那样会引起一个ConcurrentModificationException异常,所以使用一个常规的for循环来代替,而是向后退步。

 List<Integer> integerList; integerList = new ArrayList<Integer>(); integerList.add(1); integerList.add(2); integerList.add(3); int size= integerList.size(); //Item to remove Integer remove = Integer.valueOf(3); 

一个办法:

如果要删除列表元素,请按相反顺序遍历数组。 简单地通过向后浏览列表可以避免访问已经被移除的项目,这将移除异常。

 //To remove items from the list, start from the end and go backwards through the arrayList //This way if we remove one from the beginning as we go through, then we will avoid getting a runtime error //for java.lang.IndexOutOfBoundsException or java.util.ConcurrentModificationException as when we used the iterator for (int i=size-1; i> -1; i--) { if (integerList.get(i).equals(remove) ) { integerList.remove(i); } } 

这段代码总是会抛出一个ConcurrentModificationException异常。

规则是“你可能不会修改(添加或从列表中删除元素),而使用迭代器(当你使用for-each循环时发生)”迭代它。

JavaDoc中:

这个类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在迭代器创建之后,在任何时候结构性地修改列表,除了通过迭代器自己的remove或add方法以外,迭代器将抛出一个ConcurrentModificationException异常。

因此,如果你想修改列表(或一般的任何集合),使用迭代器,因为它知道修改,因此这些将被正确处理。

希望这可以帮助。

我有同样的问题,但万一我将元素添加到迭代列表。 我是这样做的

 public static void remove(Integer remove) { for(int i=0; i<integerList.size(); i++) { //here is maybe fine to deal with integerList.get(i)==null if(integerList.get(i).equals(remove)) { integerList.remove(i); } } } 

现在一切正常,因为你不会在你的列表上创建任何迭代器,你可以“手动”地迭代它。 而条件i < integerList.size()永远不会欺骗你,因为当你删除/添加列表的大小列表递减/增量。

希望它有帮助,对我来说这是解决方案。

这在Java 1.6上运行良好

〜%javac RemoveListElementDemo.java
〜%java RemoveListElementDemo
〜%猫RemoveListElementDemo.java

 import java.util.*; public class RemoveListElementDemo { private static final List<Integer> integerList; static { integerList = new ArrayList<Integer>(); integerList.add(1); integerList.add(2); integerList.add(3); } public static void remove(Integer remove) { for(Integer integer : integerList) { if(integer.equals(remove)) { integerList.remove(integer); } } } public static void main(String... args) { remove(Integer.valueOf(2)); Integer remove = Integer.valueOf(3); for(Integer integer : integerList) { if(integer.equals(remove)) { integerList.remove(integer); } } } } 

〜%

如果你使用copy-on-write集合,它将会工作。 但是当你使用list.iterator()时,即使另一个线程修改了这个集合,返回的Iterator也总是引用这个元素的集合,就像调用list.iterator()时一样。 任何在基于写时拷贝的Iterator或ListIterator上调用的变异方法(例如add,set或remove)都会抛出UnsupportedOperationException异常。

 import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class RemoveListElementDemo { private static final List<Integer> integerList; static { integerList = new CopyOnWriteArrayList<>(); integerList.add(1); integerList.add(2); integerList.add(3); } public static void remove(Integer remove) { for(Integer integer : integerList) { if(integer.equals(remove)) { integerList.remove(integer); } } } public static void main(String... args) { remove(Integer.valueOf(2)); Integer remove = Integer.valueOf(3); for(Integer integer : integerList) { if(integer.equals(remove)) { integerList.remove(integer); } } } } 

检查你的代码人….

在主要的方法,你正在试图删除不存在的第四个元素,因此错误。 在remove()方法中,您试图删除第三个元素,因此没有错误。

就我而言,我是这样做的:

 int cursor = 0; do { if (integer.equals(remove)) integerList.remove(cursor); else cursor++; } while (cursor != integerList.size());