Add/Remove elements from Java ArrayList inside foreach
Foreach
is the syntactic sugar for iterator for that collection
In ArrayList’s Itr
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount; //modCount is from the list
public boolean hasNext() {
return cursor != size; //size is from the list
}
If we call ArrayList.remove()
inside foreach
to remove the non-first element in the list
- hasNext() will return true because cursor is now > size, and Itr.next() will be triggered
- next() will
checkForComodification()
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
At this moment, because we didn’t remove via iterator, the expectedModCount
will be less than modCount
, and exception will be thrown!
Note that Itr has a remove()
but does not have add
public void remove() {
if (lastRet < 0) //this check ensures that we can't call Itr.remove() twice in a row
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
In ArrayList, it has a modCount.
In ArrayList, we have an internal Itr time, which has a expectedModCount, it implments Iterator, i.e., the instance you get from ArrayList.iterator and use that to prevent concurrent change but iterator.remove is OK