Какие способы удалить элементы по условию во время обхода коллекции корректны?
Корректно: removeIf, явный Iterator.remove(), проход по индексам с конца. Удаление в for-each — CME, по индексам вперёд — пропуск элементов.
- removeIf на ArrayList — один сдвиг хвоста, а не на каждое удаление
- iterator.remove синхронизирует ожидаемый modCount
- Новый список через stream().filter() — тоже вариант
А ещё Для Map — entrySet().removeIf или values().removeIf
Подробно
Метод iterator.remove() работает потому, что итератор сам синхронизирует свой ожидаемый счётчик модификаций с коллекцией. removeIf — самый читаемый вариант и в реализациях на массиве ещё и эффективнее серии удалений, так как сдвигает хвост один раз, а не на каждый элемент. Обход по индексам с конца корректен потому, что удаление сдвигает только элементы правее текущего, которые уже обработаны. Прямое удаление через коллекцию внутри for-each — та самая ошибка, дающая ConcurrentModificationException.
Что хотят услышать
- Перечень корректных способов и почему они работают.
Частые ошибки
- Идти по индексам вперёд и удалять — каждый второй элемент будет пропущен.
- Вызывать iterator.remove() до первого next() — получите IllegalStateException.
Проверьте себя
Несколько верных вариантов. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓collection.removeIf(predicate)
- ✓Явный Iterator и вызов iterator.remove()
- ✓Обход списка по индексам с конца к началу
- ✗for-each с вызовом collection.remove(element)
Что спросят дальше
- Почему removeIf эффективнее серии remove у ArrayList?
- Что вернёт stream().filter() — изменит ли он исходную коллекцию?
Разбор темы
- Итераторы: fail-fast и ConcurrentModificationException
Iterator и ListIterator, механизм modCount, причины CME даже в одном потоке и безопасное удаление.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.