Видалення елемента списку в циклі foreach не пускає concurrentmodificationexception, чому stack
Питання скоріше теоретичний, але все ж. Припустимо, у мене є якийсь ArrayList.
І я хочу з нього видалити все числа більше 10.
"Правильно" зробити це можна через итератор, отримавши гарантований результат.
Але на моє здивування, коректно працює і варіант
Незважаючи на те, що всюди говориться, що будь-яка спроба видалення з колекції в циклі без використання ітератора призводить до ConcurrentModificationException.
І, дійсно, якщо будемо видаляти безумовно, отримаємо якраз ConcurrentModificationException
Власне, може хто-небудь пояснити магію або дати наводку, де можна почитати на цю тему?
Мабуть вам казково пощастило:
- у вас не було елементів, значення яких було більше 10
- у вас був елемент, значення якого було більше 10, але він був тільки один і розташовувався на передостанньому місці в списку
Давайте розглянемо роботу на більш короткому прикладі.
Ми додали три числа. Отже, як працює foreach
- Він отримує итератор.
Перевіряє на наявність наступного елемента hasNext ().
Якщо повертається true. то бере наступний елемент за допомогою next ().
Далі повторюються кроки 2 і 3 поки hasNext () не поверне false.
Якщо видалити елемент зі списку, то його розмір зменшиться і modCount збільшиться.
Якщо видалити елемент під час ітерації, то буде викинуто ConcurrentModificationException виняток на рядку modCount! = ExpectedModCount.
Але що відбувається, якщо видаляється передостанній елемент?
Коли ми видалимо значення 22, то розмір зменшиться до 2.
В інших же випадках буде викинуто ConcurrentModificationException через modCount! = ExpectedModCount.
А в цьому окремому випадку перевірка пройде на ура ..
Ось магія. Або баг.