Видалення елемента списку в циклі foreach не пускає concurrentmodificationexception, чому stack

Питання скоріше теоретичний, але все ж. Припустимо, у мене є якийсь ArrayList.

І я хочу з нього видалити все числа більше 10.

"Правильно" зробити це можна через итератор, отримавши гарантований результат.

Але на моє здивування, коректно працює і варіант

Незважаючи на те, що всюди говориться, що будь-яка спроба видалення з колекції в циклі без використання ітератора призводить до ConcurrentModificationException.

І, дійсно, якщо будемо видаляти безумовно, отримаємо якраз ConcurrentModificationException

Власне, може хто-небудь пояснити магію або дати наводку, де можна почитати на цю тему?

Мабуть вам казково пощастило:

  • у вас не було елементів, значення яких було більше 10
  • у вас був елемент, значення якого було більше 10, але він був тільки один і розташовувався на передостанньому місці в списку

Давайте розглянемо роботу на більш короткому прикладі.

Ми додали три числа. Отже, як працює foreach

  1. Він отримує итератор.

Перевіряє на наявність наступного елемента hasNext ().

Якщо повертається true. то бере наступний елемент за допомогою next ().

Далі повторюються кроки 2 і 3 поки hasNext () не поверне false.

Якщо видалити елемент зі списку, то його розмір зменшиться і modCount збільшиться.

Якщо видалити елемент під час ітерації, то буде викинуто ConcurrentModificationException виняток на рядку modCount! = ExpectedModCount.

Але що відбувається, якщо видаляється передостанній елемент?

Коли ми видалимо значення 22, то розмір зменшиться до 2.

В інших же випадках буде викинуто ConcurrentModificationException через modCount! = ExpectedModCount.

А в цьому окремому випадку перевірка пройде на ура ..

Ось магія. Або баг.