Ответ
ConcurrentModificationException — это unchecked исключение, которое возникает при изменении структуры коллекции (добавление, удаление элементов) во время её итерации любым способом, кроме использования методов самого итератора.
Причина: Большинство коллекций java.util (кроме потокобезопасных) имеют fail-fast итераторы, которые проверяют, не изменилась ли коллекция с момента начала итерации (по счётчику модификаций). При обнаружении изменения выбрасывается это исключение.
Пример, вызывающий исключение:
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String item : list) { // Неявно использует Iterator
if ("B".equals(item)) {
list.remove(item); // Модификация коллекции во время итерации!
}
}
Способы безопасного удаления элементов во время итерации:
-
Использование метода
Iterator.remove():Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if ("B".equals(item)) { iterator.remove(); // Корректный способ удаления } } -
Использование
removeIf()(Java 8+):list.removeIf(item -> "B".equals(item)); -
Сбор элементов для удаления в отдельную коллекцию:
List<String> toRemove = new ArrayList<>(); for (String item : list) { if ("B".equals(item)) { toRemove.add(item); } } list.removeAll(toRemove); -
Использование потокобезопасных коллекций (для многопоточного доступа):
CopyOnWriteArrayList— создаёт копию массива при изменении, итерация идёт по снимку на момент создания итератора.ConcurrentHashMap— позволяет безопасные модификации во время итерации (итератор может отражать не все последние изменения).