Как создать неизменяемую коллекцию
Короткий ответ
Фабричные методы List.of(), Set.of() и Map.of() создают коллекции, которые нельзя изменить:
void main() {
List<String> roles = List.of("admin", "editor");
Map<String, Integer> limits = Map.of("free", 10, "pro", 100);
IO.println(roles);
IO.println(limits.get("pro"));
}Результат:
[admin, editor]
100Копия существующей коллекции
List.copyOf() делает неизменяемую копию. Последующие изменения оригинала на неё не влияют:
void main() {
var names = new ArrayList<>(List.of("Anna"));
var snapshot = List.copyOf(names);
names.add("Oleg");
IO.println(names);
IO.println(snapshot);
}Результат:
[Anna, Oleg]
[Anna]Представление только для чтения
Collections.unmodifiableList() не копирует данные, а запрещает изменения через себя. Изменения оригинала в нём видны:
void main() {
var names = new ArrayList<>(List.of("Anna"));
var view = Collections.unmodifiableList(names);
names.add("Oleg");
IO.println(view);
}Результат:
[Anna, Oleg]Из потока
toList() у потока тоже возвращает неизменяемый список:
void main() {
var evens = Stream.of(1, 2, 3, 4).filter(n -> n % 2 == 0).toList();
IO.println(evens);
evens.add(6);
}Результат:
[2, 4]
Exception in thread "main" java.lang.UnsupportedOperationExceptionЧастая ошибка
Считать неизменяемыми и сами элементы. Коллекция не даёт добавить или убрать элемент, но изменяемый объект внутри неё менять можно:
void main() {
var lists = List.of(new ArrayList<>(List.of(1)));
lists.getFirst().add(2);
IO.println(lists);
}Результат:
[[1, 2]]Для полной неизменяемости элементы тоже должны быть неизменяемыми — например, записями (record) со строками и числами.
Функции из этого ответа
- List.of() — Создаёт неизменяемый список из перечисленных элементов.
- List.copyOf() — Создаёт неизменяемую копию коллекции в виде списка.
- Collections.unmodifiableList() — Возвращает представление списка, которое нельзя изменить.
- Map.of() — Создаёт неизменяемый словарь из пар «ключ — значение».