Zexi Gong
Zexi Gong

Reputation: 189

ConcurrentModificationException not thrown consistently

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);

Upvotes: 5

Views: 139

Answers (1)

Michał Krzywański
Michał Krzywański

Reputation: 16900

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.

Upvotes: 5

Related Questions