Что такое Collections.unmodifiableList()?
Обёртка защищает только структуру списка (добавление/удаление элементов), но не сами объекты. Если нужна глубокая неизменяемость — делайте User immutable (final поля, нет setter...
🟢 Junior Level
unmodifiableList — обёртка, которая запрещает изменять список.
List<String> list = new ArrayList<>(List.of("A", "B"));
List<String> unmod = Collections.unmodifiableList(list);
unmod.get(0); // ✅ OK → "A"
unmod.add("C"); // ❌ UnsupportedOperationException!
ВАЖНО: это представление (view), не копия!
list.add("C"); // Изменили оригинал
unmod.get(2); // → "C" (изменение видно!)
🟡 Middle Level
View vs Immutable
// View (unmodifiableList):
List<String> view = Collections.unmodifiableList(original);
original.add("X"); // Изменение видно в view!
// Immutable (List.of):
List<String> immutable = List.of("A", "B");
// → Нельзя изменить НИЧЕМ
// → Нет связи с оригиналом
unmodifiableCollection возвращает Collection (нет get(int), subList). unmodifiableList возвращает List (сохраняет индексный доступ). Используйте unmodifiableList, когда вызывающему коду нужны методы List.
Когда использовать
// ✅ Защита внутреннего состояния
public class UserService {
private List<User> users = new ArrayList<>();
public List<User> getUsers() {
return Collections.unmodifiableList(users);
// Клиент не сможет изменить внутренний список!
}
}
// ✅ Read-only доступ
public void printAll(List<String> list) {
List<String> readOnly = Collections.unmodifiableList(list);
// Гарантия: метод не изменит список
}
Не защищает объекты внутри
List<User> users = Collections.unmodifiableList(list);
users.get(0).setName("Hacker"); // ✅ Можно!
// → Обёртка защищает структуру списка, не объекты!
Обёртка защищает только структуру списка (добавление/удаление элементов), но не сами объекты. Если нужна глубокая неизменяемость — делайте User immutable (final поля, нет setter’ов) или используйте deep copy при обёртывании.
🔴 Senior Level
Когда НЕ использовать unmodifiableList
- Нужна настоящая иммутабельность — используйте
List.copyOf()(Java 10+) - Нужна защита от рефлексии — unmodifiableList уязвим
- Коллекция будет меняться из другого потока — нужна синхронизация оригинала
RandomAccess preservation
// ArrayList implements RandomAccess
// UnmodifiableRandomAccessList тоже!
// → binarySearch работает оптимально
// LinkedList НЕ RandomAccess
// UnmodifiableList тоже НЕ RandomAccess
List.copyOf (Java 10+)
// Копия → нет связи с оригиналом
List<String> copy = List.copyOf(original);
original.add("X"); // Не видно в copy!
// unmodifiableList → view → связь есть
// List.copyOf → копия → связи нет
Defensive Copying
// API сервисов:
// unmodifiableList → клиент может добраться до оригинала
// List.copyOf → полная изоляция (безопаснее)
// Но: List.copyOf = O(n) копирование
// unmodifiableList = O(1) обёртка
Production Experience
Реальный сценарий: утечка оригинала
// ❌ Клиент нашёл оригинал через рефлексию
List<String> view = Collections.unmodifiableList(secret);
// → Нашёл поле list внутри обёртки
// → Изменил!
// ✅ List.copyOf → нет оригинала
List<String> safe = List.copyOf(secret);
Best Practices
- unmodifiableList = view, не immutable
- List.copyOf = полная изоляция
- Объекты внутри можно менять
- RandomAccess сохраняется
- Defensive copy для security-critical
- O(1) создание vs O(n) копирование
Резюме для Senior
- View → связь с оригиналом
- List.copyOf → изоляция
- Не защищает объекты внутри
- RandomAccess сохраняется
- O(1) создание обёртки
- Defensive copy для security
🎯 Шпаргалка для интервью
Обязательно знать:
unmodifiableList()возвращает view (представление), не копию — изменения оригинала видны- Любая модификация (
add,remove,set) бросаетUnsupportedOperationException - Обёртка защищает структуру списка, но НЕ объекты внутри (mutable User можно изменить)
unmodifiableListvsList.copyOf(): view (связь с оригиналом) vs полная копия (изоляция)RandomAccessмаркер сохраняется — оптимизация для бинарного поиска- Создание обёртки O(1), копирование
List.copyOf()O(n) - Для security-critical кода —
List.copyOf()или defensive copy
Частые уточняющие вопросы:
- Видны ли изменения оригинала через unmodifiableList? — Да, это view, не копия.
- Защищает ли unmodifiableList от изменения объектов внутри списка? — Нет, только от изменения структуры списка (add/remove). Сами объекты нужно делать immutable.
- Когда выбрать List.copyOf() вместо unmodifiableList()? — Когда нужна полная изоляция от оригинала (Java 10+).
- Сохраняется ли RandomAccess через обёртку? — Да,
UnmodifiableRandomAccessListтожеimplements RandomAccess.
Красные флаги (НЕ говорить):
- «unmodifiableList создаёт копию данных» — нет, это view на оригинал
- «unmodifiableList — это настоящая иммутабельность» — нет, оригинал можно изменить
- «Объекты внутри тоже защищены» — обёртка защищает только структуру, не содержимое
- «List.copyOf() — то же самое, что unmodifiableList» — List.copyOf() создаёт копию, без связи с оригиналом
Связанные темы:
- [[24. Как работает Collections.unmodifiableList() внутри]]
- [[22. Как получить synchronized коллекцию]]
- [[31. Какие операции поддерживает интерфейс Collection]]