Что такое мутабельность
Что проверяют
Различаете ли вы изменяемость объекта и неизменяемость ссылки, и понимаете ли, почему неизменяемость убирает целый класс ошибок многопоточности бесплатно, без единой блокировки.
Как отвечать
Мутабельный объект меняет состояние после создания: ArrayList, StringBuilder, обычный класс с сеттерами. Иммутабельный не меняет: String, обёртки примитивов, классы даты и времени, запись из финальных полей.
Главная проверка по теме звучит так: final относится к ссылке, а не к содержимому. Объявление final List<String> items запрещает присвоить другой список, но items.add(...) работает прекрасно.
Рецепт неизменяемого класса: запретить наследование, все поля сделать приватными и финальными, не заводить сеттеров, а изменяемые поля копировать и при приёме в конструкторе, и при возврате. Без защитных копий список, переданный снаружи, остаётся у вызывающего кода, и он меняет ваше состояние в обход всех правил.
Зачем это нужно: неизменяемый объект безопасно публиковать между потоками без синхронизации, его можно без страха класть ключом в отображение, а строка кеширует свой хеш и живёт в пуле именно потому, что не меняется.
Цена тоже есть: при частых изменениях рождается много объектов, поэтому строки в цикле склеивают через StringBuilder. Рабочий компромисс это неизменяемое ядро данных и изменяемый сборщик рядом.
Где спотыкаются
Считают, что финальное поле делает объект неизменяемым, и на этом останавливаются. Отсюда классы, которые называются неизменяемыми, но отдают наружу живую коллекцию.
Возвращают внутреннюю коллекцию как есть, с аргументом, что поле приватное. Обёртка unmodifiableList спасает только от записи через полученную ссылку: это представление, которое меняется вместе с исходным списком. Независимую копию дают List.copyOf и List.of.
Кладут изменяемый объект ключом в отображение, а потом правят поле, участвующее в hashCode. Запись остаётся в таблице, но не находится ни по старому ключу, ни по новому, и утечка выглядит как мистика.