Что такое Fail-Fast механизм при модификации коллекции в Java?

«Что такое Fail-Fast механизм при модификации коллекции в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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
    }
}

Правильные подходы:

  1. Использовать метод remove() самого итератора:
    Iterator<String> it = list.iterator();
    while (it.hasNext()) {
    String s = it.next();
    if (s.equals("b")) {
        it.remove(); // Безопасно, корректирует expectedModCount
    }
    }
  2. Использовать потокобезопасные коллекции (например, CopyOnWriteArrayList), которые реализуют Fail-Safe поведение.
  3. Собирать элементы для удаления в отдельный список и выполнять удаление после итерации.

Цель: предотвратить недетерминированное поведение и потенциальную порчу данных, когда логика итерации основана на предположениях о неизменности структуры коллекции во время её обхода.