Что такое fail fast и чем он отличается от fail safe
Что проверяют
Знаете ли вы, что в Java эти слова чаще всего про итераторы коллекций, и понимаете ли, почему одни бросают исключение при изменении, а другие нет. Общий ответ про принципы проектирования интервьюер выслушает, но добьёт вопросом про ConcurrentModificationException.
Как отвечать
Дайте два определения и сразу переведите разговор на коллекции.
Fail-fast итератор обнаруживает структурное изменение коллекции во время обхода и немедленно бросает ConcurrentModificationException. Так устроены ArrayList, HashMap, LinkedList: коллекция держит счётчик изменений, итератор запоминает его при создании и сверяет на каждом шаге.
Fail-safe итератор изменением не ломается, но механизмы у него разные. CopyOnWriteArrayList обходит снимок массива, сделанный при создании итератора, и новые элементы в нём не появятся. Итератор ConcurrentHashMap слабо согласован: он не бросает исключение и может увидеть часть изменений, внесённых уже после начала обхода.
Удалять элемент при обходе нужно через сам итератор:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (it.next().isEmpty()) it.remove();
}Компромисс формулируйте так: fail-fast сообщает об ошибке в вашем коде сразу и в месте её появления, fail-safe даёт обход без исключений ценой устаревших данных, а у копирующих коллекций ещё и ценой копии массива на каждую запись.
Где спотыкаются
Называют ConcurrentModificationException гарантией потокобезопасности. Проверка счётчика сделана по принципу лучшего усилия, строить на ней логику нельзя, и отсутствие исключения ничего не доказывает.
Путают структурное изменение с изменением значения. Замена элемента через set или правка полей самого объекта итератор не ломают, ломают добавление и удаление.
Не знают углового случая ArrayList: удаление предпоследнего элемента через коллекцию исключения не даст, потому что обход закончится раньше очередной проверки. Отсюда живучие ошибки, которые проявляются только на определённой длине списка.