Удаление элемента списка в цикле foreach не бросает ConcurrentModificationException, почему?

1,00
р.
Допустим, у меня есть некий ArrayList.
ArrayList list = new ArrayList<>()
for (int i = 0 i < 10 i++) list.add((int) (Math.random() * 20))
И я хочу из него удалить все числа больше 10.
"Правильно" сделать это можно через итератор, получив гарантированный результат.
for (Iterator iterator = list.iterator() iterator.hasNext() ) if (iterator.next() > 10) iterator.remove()
Но на мое удивление, корректно работает и вариант:
for (Integer i : list) if (i > 10) list.remove(i)
Несмотря на то, что везде говорится, что любая попытка удаления из коллекции в цикле без использования итератора приводит к ConcurrentModificationException.
И, действительно, если будем удалять безусловно, получим как раз ConcurrentModificationException
for (Integer i : list) list.remove(i)
Собственно, может кто-нибудь объяснить магию или дать наводку, где можно почитать на эту тему?

Ответ
Видимо вам сказочно повезло:
у вас не было элементов, значение которых было больше 10 у вас был элемент, значение которого было больше 10, но он был только один и располагался на предпоследнем месте в списке
Давайте рассмотрим работу на более коротком примере.
ArrayList list = new ArrayList<>() list.add(1) list.add(22) list.add(3)
Мы добавили три числа. Итак, как работает foreach
Он получает итератор. Проверяет на наличие следующего элемента hasNext(). public boolean hasNext() { return cursor != size() // cursor is zero initially. }
Если возвращается true, то берет следующий элемент с помощьюnext(). public E next() { checkForComodification() try { E next = get(cursor) lastRet = cursor++ return next } catch (IndexOutOfBoundsException e) { checkForComodification() throw new NoSuchElementException() } }
final void checkForComodification() { // Initially modCount = expectedModCount (our case 5) if (modCount != expectedModCount) throw new ConcurrentModificationException() }

Далее повторяются шаги 2 и 3 пока hasNext() не вернет false.
Если удалить элемент из списка, то его размер уменьшится и modCount увеличится.
Если удалить элемент во время итерации, то будет выброшено ConcurrentModificationException исключение на строке modCount != expectedModCount.

Но что происходит, если удаляется предпоследний элемент?
> cursor = 0 size = 3 --> hasNext() успешно и next() тоже без эксепшена > cursor = 1 size = 3 --> hasNext() успешно и next() тоже без эксепшена
Когда мы удалим значение 22, то размер уменьшится до 2.
> cursor = 2 size = 2 --> hasNext() не успешно и next() пропускается.
В других же случаях будет выброшено ConcurrentModificationException из-за modCount != expectedModCount.
А в этом единичном случае проверка пройдет на ура..
Вот магия....Или баг....