Ответ
Fail-Fast — это поведение некоторых коллекций Java (например, ArrayList, HashMap), при котором итератор немедленно выбрасывает ConcurrentModificationException, если коллекция была структурно изменена после создания итератора любым способом, кроме методов самого итератора.
Принцип работы:
- Каждая коллекция содержит внутренний счётчик
modCount(modification count). - При любом структурном изменении (добавление, удаление)
modCountувеличивается. - Итератор при создании запоминает текущее значение
modCountкакexpectedModCount. - При каждом вызове
next()илиremove()итератор проверяет, чтоmodCount == expectedModCount. Если нет — выбрасывается исключение.
Пример, вызывающий исключение:
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
for (String s : list) { // Неявно создаётся итератор
if (s.equals("b")) {
list.remove(s); // Прямое изменение коллекции! ConcurrentModificationException
}
}
Правильные подходы:
- Использовать метод
remove()самого итератора:Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); if (s.equals("b")) { it.remove(); // Безопасно, корректирует expectedModCount } } - Использовать потокобезопасные коллекции (например,
CopyOnWriteArrayList), которые реализуют Fail-Safe поведение. - Собирать элементы для удаления в отдельный список и выполнять удаление после итерации.
Цель: предотвратить недетерминированное поведение и потенциальную порчу данных, когда логика итерации основана на предположениях о неизменности структуры коллекции во время её обхода.