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