为什么我没有在这个例子中得到一个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());