Collections.unmodifiableSet: примеры (JAVA)
Collections.unmodifiableSet(Set extends T> s): SetОписание и сигнатуры
Метод Collections.unmodifiableSet() возвращает неизменяемое представление (view) заданного множества. Под неизменяемым представлением понимается объект типа Set, методы модификации которого (add, remove, clear и т. п.) выбрасывают UnsupportedOperationException. Сигнатура метода:
public static <T> Set<T> unmodifiableSet(Set<? extends T> s)
Основные свойства и поведение:
- Если переданный аргумент
sравенnull, выбрасываетсяNullPointerException. - Возвращается «обертка» над исходным множеством. Если исходное множество изменяется напрямую (через ссылку на него), изменения будут видны в возвращаемом наборе.
- Попытка изменить возвращаемое множество через его API приводит к
UnsupportedOperationException. Аналогично, итератор, полученный у обертки, запрещает операциюremove()и выбрасываетUnsupportedOperationException. - Возвращаемая обертка сериализуется только если сериализуемо исходное множество; иначе сериализация обертки не будет возможна.
- Метод доступен с ранних версий Java (Collections появился в Java 1.2). Семантика не изменилась: это view, а не копия или «настоящая» неизменяемая структура.
Применимость: когда требуется предоставить клиенту доступ к множеству для чтения, одновременно сохраняя возможность изменения исходного множества внутри текущего модуля. Для получения полностью неизменяемого набора (копии) лучше рассмотреть фабричные методы Set.of или Set.copyOf.
Короткие примеры использования
1) Простая обертка и попытка модификации
import java.util.*;
class Demo1 {
public static void main(String[] args) {
Set<String> original = new HashSet<>(Arrays.asList("a", "b"));
Set<String> view = Collections.unmodifiableSet(original);
System.out.println("view before: " + view);
try {
view.add("c");
} catch (UnsupportedOperationException e) {
System.out.println("caught: " + e.getClass().getSimpleName());
}
}
}
view before: [a, b] caught: UnsupportedOperationException
2) Изменение исходного множества отражается в представлении
import java.util.*;
class Demo2 {
public static void main(String[] args) {
Set<String> original = new HashSet<><>(Arrays.asList("x"));
Set<String> view = Collections.unmodifiableSet(original);
System.out.println("before: " + view);
original.add("y");
System.out.println("after original.add: " + view);
}
}
before: [x] after original.add: [x, y]
3) NullPointerException при передаче null
Set<String> view = Collections.unmodifiableSet(null); // NPE
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:246)
at java.base/java.util.Collections.unmodifiableSet(Collections.java:___)
4) Итератор обертки и remove()
Set<String> original = new HashSet<>(Arrays.asList("p", "q"));
Set<String> view = Collections.unmodifiableSet(original);
Iterator<String> it = view.iterator();
if (it.hasNext()) {
it.next();
it.remove(); // UnsupportedOperationException
}
Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.Collections$UnmodifiableCollection$1.remove(Collections.java:___)Похожие API в Java и их особенности
- Collections.unmodifiableList/Map/Collection/SortedSet/NavigableSet - те же семантика и ограничение, но для других коллекций. Выбирать по типу коллекции.
- Set.of(...) (Java 9) - фабричные методы создают реально неизменяемые наборы; при попытке модификации полученного объекта также будет
UnsupportedOperationException, но это не view: оригинальная копия не может быть изменена и не отражает внешние изменения. - Set.copyOf(...) (Java 10) - создаёт неглубокую копию в виде неизменяемого набора; предпочтительнее когда нужна гарантированная неизменность копии.
- Guava ImmutableSet - библиотечная реализация истинно неизменяемого множества с полезными утилитами и оптимизациями; удобна при интенсивном использовании неизменяемых структур.
Когда что предпочесть:
- Если требуется только запрет на модификацию API для внешних пользователей, но внутренние изменения должны быть видны -
Collections.unmodifiableSet. - Если требуется гарантировать полную неизменность и отсутствие сторонних изменений -
Set.of,Set.copyOfилиImmutableSet.
Аналоги в других языках и отличия
Краткие сравнения с примерами.
- Python:
frozenset- действительно неизменяемый набор (копия/тип), пример:
s = frozenset(['a', 'b'])
try:
s.add('c')
except AttributeError as e:
print(type(e).__name__)
AttributeError
- JavaScript: нет встроенного неизменяемого Set; возможен Proxy для запрета модификаций:
const s = new Set(['a','b']);
const proxy = new Proxy(s, {
get(target, prop) {
if (prop === 'add' || prop === 'delete' || prop === 'clear') {
return () => { throw new Error('Unsupported'); };
}
return target[prop];
}
});
try { proxy.add('c'); } catch(e) { console.log(e.message); }
Unsupported
- C#:
ReadOnlyCollectionдля списков или создание копии вHashSetи предоставление интерфейсаIReadOnlyCollection<T>. Пример создания обертки черезAsReadOnlyдля списка. - Go: наборов как встроенного типа нет; обычно используют map[T]struct{} и договор о неиспользовании модифицирующих операций либо копирование данных для иммутабельности.
- Kotlin:
setOfвозвращает неизменяемое множество (интерфейс),Collections.unmodifiableSetтоже доступен из Java-интеропа. Kotlin разделяет mutable/immutable коллекции. - PHP: нет встроенного immutable set; используются массивы или SplObjectStorage и сторонние библиотеки для иммутабельности.
- Lua: таблицы используются как наборы; иммутабельность достигается соглашением или метатаблицами, запрещающими запись.
- SQL: понятие набора данных в запросе нерелевантно; неизменяемость данных достигается правами доступа и транзакциями.
Отличия от Java: в большинстве языков либо предоставляется реальная неизменяемость (Python frozenset, Kotlin setOf), либо приходится использовать соглашения/прокси. Java Collections.unmodifiableSet - это view, а не копия, что важно учитывать при выборе.
Типичные ошибки и ловушки
- Ожидание полной неизменяемости. Частая ошибка - считать, что возвращаемое множество абсолютно неизменяемо. На самом деле это view: если модифицировать оригинал, изменения будут видны в обертке. Пример:
Set<String> orig = new HashSet<>();
orig.add("1");
Set<String> v = Collections.unmodifiableSet(orig);
orig.add("2");
System.out.println(v); // [1, 2]
[1, 2]
- NullPointerException при передаче null. Исправление: проверять аргумент или использовать Optional/фабрики.
- UnsupportedOperationException при модификации через view. Пример попытки
addилиiterator().remove()у обертки. - Ошибки многопоточности. Обертка не делает структуру потокобезопасной. Частая ошибка - передача несинхронизированного множества между потоками и ожидание безопасности. В этом случае возможны race condition и ConcurrentModificationException при итерации.
- Ошибка сериализации}. Если обертка сериализуется, то сериализуется содержимое исходного множества только при условии, что исходное множество сериализуемо; иначе при попытке сериализовать будет исключение.
Изменения в последних версиях Java
- Сигнатура и поведение
Collections.unmodifiableSetостаются стабильными с ранних версий Java. Это view-обертка, и это не изменялось. - Java 9 представила фабрики коллекций (
Set.ofи пр.), которые создают действительно неизменяемые коллекции. Это повлияло на рекомендации: для гарантированной неизменяемости теперь чаще предлагается использоватьSet.ofили сторонние immutable-реализации. - Java 10 добавила методы копирования коллекций (
Set.copyOf,List.copyOf), позволяющие быстро получить неизменяемую копию исходной коллекции.
Расширенные и редкие сценарии использования
1) Возвращать чтение-ориентированное API из метода, сохраняя возможность менять внутреннее состояние:
public class ConfigStore {
private final Set<String> flags = new HashSet<>();
public Set<String> getFlags() {
return Collections.unmodifiableSet(flags);
}
// внутреннее изменение доступно
void enable(String f) { flags.add(f); }
}
// Клиент может читать но не менять: cfg.getFlags().add("x") -> UnsupportedOperationException
2) Обьединение с синхронизацией: безопасное использование в многопоточном окружении
Set<String> sync = Collections.synchronizedSet(new HashSet<>());
Set<String> view = Collections.unmodifiableSet(sync);
// При итерации требуется внешняя синхронизация по sync
synchronized(sync) {
for (String v : view) {
System.out.println(v);
}
}
(печать элементов без race condition при соблюдении синхронизации)
3) Обертка над сортированным множеством
SortedSet<Integer> sorted = new TreeSet<><>(Arrays.asList(3,1,2));
SortedSet<Integer> ro = Collections.unmodifiableSortedSet(sorted);
System.out.println(ro.first() + ", " + ro.last());
1, 3
4) Комбинация с ConcurrentHashMap.newKeySet() для «приближения» к потокобезопасному неизменяемому виду:
Set<String> concurrent = ConcurrentHashMap.newKeySet();
concurrent.add("a");
Set<String> view = Collections.unmodifiableSet(concurrent);
// concurrent можно модифицировать из других потоков, view не позволит модифицировать через свое API
(view нельзя изменить через его методы; concurrent может изменяться параллельно)
5) Сериализация обертки (только при сериализуемом внутреннем наборе)
// При сериализации Collections.unmodifiableSet(serializableSet) данные внутреннего множества сохранятся
// При десериализации будет восстановлена обертка и внутреннее состояние
(если внутренний Set реализует Serializable, сериализация пройдет успешно)
6) Использование вместо коллектора для получения неизменяемого множества (в новых версиях Java)
// Collectors.toUnmodifiableSet() создает истинно неизменяемый набор (Java 10+)
Set<String> s = Stream.of("a","b").collect(Collectors.toUnmodifiableSet());
s.add("c") -> UnsupportedOperationException (и это не view)
Комментарий: сочетание Collections.unmodifiableSet с другими утилитами полезно для управления видимостью и безопасностью API. Если требуется гарантированная иммутабельность, предпочтение у Set.of, Set.copyOf или библиотечных реализаций.
джава Collections.unmodifiableSet function comments
- джава Collections.unmodifiableSet - аргументы и возвращаемое значение
- Функция java Collections.unmodifiableSet - описание
- Collections.unmodifiableSet - примеры
- Collections.unmodifiableSet - похожие методы на java
- Collections.unmodifiableSet на javascript, c#, python, php
- Collections.unmodifiableSet изменения java
- Примеры Collections.unmodifiableSet на джава