Ответ
Неизменяемость String является фундаментальным свойством, которое обеспечивает корректную и безопасную работу при использовании строк в качестве ключей в хэш-коллекциях (HashMap, HashSet, ConcurrentHashMap).
Ключевые причины:
-
Гарантия постоянства хэш-кода (
hashCode()). Позиция объекта в хэш-таблице определяется его хэш-кодом на момент помещения. Если после добавления ключа изменить его состояние (что невозможно дляString), хэш-код изменится. Последующий поиск поget(key)будет выполняться по новому хэш-коду в другой "корзине" (bucket), и элемент не будет найден, хотя физически он останется в коллекции (утечка памяти и логическая ошибка). -
Сохранение контракта между
equals()иhashCode(). Контракт требует, чтобы равные объекты имели равные хэш-коды. Изменение ключа может нарушить это правило, сделав коллекцию неконсистентной. -
Потокобезопасность. Неизменяемые объекты по своей природе потокобезопасны. Ключ может быть безопасно использован из нескольких потоков без риска состояния гонки (race condition) и без необходимости в синхронизации.
Наглядный пример проблемы с изменяемым ключом:
// Демонстрация гипотетической проблемы, если бы String был изменяемым
public class MutableKeyDemo {
public static void main(String[] args) {
Map<String, Integer> budget = new HashMap<>();
String key = "java";
budget.put(key, 100); // Хэш-код вычисляется от "java"
// Гипотетический метод, изменяющий внутреннее состояние строки
// key.mutateTo("JAVA"); // Если бы это было возможно...
// Поиск по исходному ключу "java" теперь может не сработать,
// так как его хэш-код изменился.
Integer value = budget.get(key); // Может вернуть null
System.out.println("Бюджет на " + key + ": " + value);
}
}
Вывод: Использование неизменяемых типов для ключей — это best practice, предотвращающее тонкие и сложные в отладке ошибки в логике работы коллекций.