Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConcurrentModificationException not thrown consistently

Tags:

java

iterator

Using list.remove((Object)93) causes a ConcurrentModificationException in this example:

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(14);
list.add(2);
list.add(44);
list.add(41);
list.add(93);
list.add(20);

for(Iterator<Integer> it = list.iterator();it.hasNext();) {
    list.remove((Object)93);
    it.next();
}
System.out.println(list);

However, when I wrap list.remove((Object)93) in a if statement, it doesn't cause any errors. Why?

for(Iterator<Integer> it = list.iterator();it.hasNext();) {
    int num = it.next();
    if(num == 93) {
        list.remove((Object)93);
    }
}
System.out.println(list);
like image 756
Zexi Gong Avatar asked Dec 16 '19 15:12

Zexi Gong


1 Answers

In the first example you get the ConcurrentModificationException at the first iteration and this is expected since you modified the list while iterating with iterator.

In the second example after removing the 93 from your ArrayList the it.next() will not even be called because hasNext will return false - see the implementation of ArrayList.Itr::hasNext :

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

it only check if ArrayList size is different than the cursor. In your example the 93 element is placed in the last but one place. After removing the 93 element the size will decrease by one so it.next() will evaluate to false and it.next will not be called and no exception is thrown.

This is a coincidence that you placed 93 at the one before last place so you did not receive the exception. Try to add another value to ArrayList after 93 and ConcurrentModificationException will be thrown like in the first example.

like image 166
Michał Krzywański Avatar answered Sep 29 '22 10:09

Michał Krzywański