简体   繁体   English

ArrayList删除时出现Java ConcurrentModificationException

[英]Java ConcurrentModificationException when on ArrayList Deletion

When the Size of the ArrayList is 2, and we perform the deletion operation using foreach loop, it prints the last element, no exception is thrown, 当ArrayList的大小为2时,我们使用foreach循环执行删除操作,它将打印最后一个元素,不会引发任何异常,

for example : 例如 :

ArrayList<String> a= new ArrayList<String>(Arrays.asList("abc","xyz"));
    for(String i : a){
        a.remove(i);
    }
// a contains "xyz"

but when we increase the size of the arrayList more than 2, and perform the operation it shows concurrentModificationException. 但是,当我们将arrayList的大小增加到大于2并执行该操作时,它将显示current并发ModificationException。 Why it is showing such behavior(it works for 2 elements but not for more than 2)? 为什么它显示这种行为(它适用于2个元素,但不能超过2个)?

It is a quirk of the implementation. 这是实现的怪癖。

The exception is thrown on a best-effort basis only, there is no guarantee it will be thrown. 仅在尽力而为的基础上引发该异常,但不能保证会引发该异常。

To understand why, you need to understand how enhanced for loops are desugared: 要了解原因,您需要了解如何简化for循环:

for (String i : a) {
  a.remove(i);
}

Is compiled to something like: 被编译成类似:

Iterator<String> it = a.iterator();
while (it.hasNext()) {
  String i = a.next();
  a.remove(i);
}

Next, the iterator is implemented something like: 接下来,实现迭代器,如下所示:

int idx = 0;

boolean hasNext() {
  return idx < a.size();
}

Object next() {
  checkForModification(); // throws exception if list has been modified.
  return a.get(idx++);
}

So, if the list has size 2 initially, execution of the loop proceeds thus: 因此,如果列表最初的大小为2,则循环的执行将继续:

  • Check hasNext() : idx == 0 , and 0 < 2 is true, so it returns true. 检查hasNext()idx == 0 ,并且0 < 2为true,因此返回true。
  • Call next() : retrieve i = a.get(0) , increment idx , so idx == 1 . 调用next() :检索i = a.get(0) ,增加idx ,因此idx == 1
  • Remove i from a . 删除ia Now a.size() == 1 . 现在a.size() == 1

The loop has executed once. 循环执行一次。 Now it executes again: 现在,它再次执行:

  • Check hasNext() : idx == 1 , and 1 < 1 is false, so it returns false. 检查hasNext()idx == 1 ,并且1 < 1为false,因此返回false。

So execution stops, no ConcurrentModificationException . 因此执行停止,没有ConcurrentModificationException The list still contains the initial second item. 该列表仍包含最初的第二项。

If the list is any bigger than 2 initially, the loop executes a second time, (because idx == 1 , and size() == initial size() - 1 , so idx < initial size() - 1 ), so next() will be called again after the remove() . 如果列表最初大于2,则循环第二次执行(因为idx == 1 ,并且size() == initial size() - 1 ,所以idx < initial size() - 1 ),所以next()将在remove()之后再次调用。 The list has been modified, so checkForModification() throws an exception. 该列表已被修改,因此checkForModification()引发异常。

ArrayList is not thread safe and you can have this type of trouble while you are changing the structure of it and iterating. ArrayList不是线程安全的,并且在更改它的结构并进行迭代时可能会遇到此类问题。

You need to use an Iterator to safely remove from a collection while iterating over it. 您需要使用Iterator在迭代集合时安全地将其从集合中删除。

ArrayList<String> a= new ArrayList<String>(Arrays.asList("abc","xyz"));
for (Iterator<String> iterator = a.iterator(); iterator.hasNext();) {
    String string = iterator.next(); // pick one element

    // do some stuffs with the content

    iterator.remove(); // remove element
}

You cannot remove items from list while iterating it. 您无法在迭代过程中从列表中删除项目。 Use iterator instead. 请改用迭代器。 Look over there: 看那边:

Remove elements from collection while iterating 迭代时从集合中删除元素

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM