Что произойдет при изменении коллекции во время итерации в Java?

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

Ответ

Попытка изменить структуру коллекции (добавить или удалить элементы) во время итерации по ней с помощью Iterator или цикла for-each приведет к выбросу ConcurrentModificationException. Это защитный механизм, предотвращающий недетерминированное поведение.

Пример, вызывающий исключение:

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String item : list) {
    if (item.equals("B")) {
        list.remove(item); // ConcurrentModificationException!
    }
}

Безопасные способы изменения коллекции во время обхода:

  1. Использование Iterator.remove(): Позволяет безопасно удалять текущий элемент.

    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
        String item = iterator.next();
        if (item.equals("B")) {
            iterator.remove(); // Корректное удаление
        }
    }
  2. Создание копии коллекции для итерации: Итерируем по копии, а изменяем оригинал.

    new ArrayList<>(list).forEach(item -> {
        if (item.equals("B")) {
            list.remove(item); // Безопасно, так как итерация по копии
        }
    });
  3. Использование потокобезопасных коллекций: Например, CopyOnWriteArrayList создает новую копию внутреннего массива при каждой модификации, что позволяет безопасно итерироваться по старой версии.

    List<String> safeList = new CopyOnWriteArrayList<>(Arrays.asList("A", "B", "C"));
    for (String item : safeList) {
        if (item.equals("B")) {
            safeList.remove(item); // Без исключения
        }
    }

Важно: Изменение значения элемента (например, поля объекта в коллекции) через существующую ссылку не вызывает исключения, так как не меняет структуру самой коллекции.