Що таке Collections.unmodifiableList()?
Обгортка захищає тільки структуру списку (додавання/видалення елементів), але не самі об'єкти. Якщо потрібна глибока незмінюваність — робіть User immutable (final поля, немає se...
🟢 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]]