«1. Введение

В этом уроке мы рассмотрим различные способы создания неизменяемого множества в Java.

Но сначала давайте разберемся с неизменяемым множеством и посмотрим, зачем оно нам нужно.

2. Что такое неизменяемый набор?

В общем случае неизменяемый объект не изменит своего внутреннего состояния после того, как мы его создадим. Это делает его потокобезопасным по умолчанию. Та же логика применима к неизменяемым множествам.

Предположим, у нас есть экземпляр HashSet с некоторыми значениями. Сделав его неизменяемым, мы создадим версию нашего набора, доступную только для чтения. Таким образом, любая попытка изменить его состояние вызовет исключение UnsupportedOperationException.

Итак, зачем нам это нужно?

Конечно, наиболее распространенный вариант использования неизменяемого набора — многопоточная среда. Таким образом, мы можем обмениваться неизменяемыми данными между потоками, не беспокоясь о синхронизации.

Между тем, следует помнить о важном моменте: неизменность относится только к множеству, а не к его элементам. Кроме того, мы можем без проблем изменять ссылки экземпляров элементов набора.

3. Создание неизменяемых наборов в Core Java

Имея в нашем распоряжении только базовые классы Java, мы можем использовать метод Collections.unmodifiedSet() для переноса исходного набора.

Во-первых, давайте создадим простой экземпляр HashSet и инициализируем его строковыми значениями:

Set<String> set = new HashSet<>();
set.add("Canada");
set.add("USA");

Затем завершим его с помощью Collections.unmodifiableSet():

Set<String> unmodifiableSet = Collections.unmodifiableSet(set);

Наконец, чтобы убедиться, что наш немодифицируемый набор instance неизменяем, давайте создадим простой тестовый пример:

@Test(expected = UnsupportedOperationException.class)
public void testUnmodifiableSet() {
    // create and initialize the set instance

    Set<String> unmodifiableSet = Collections.unmodifiableSet(set);
    unmodifiableSet.add("Costa Rica");
}

Как мы и ожидали, тест пройдет успешно. Кроме того, операция add() запрещена для экземпляра немодифицируемого набора и вызовет исключение UnsupportedOperationException.

Теперь давайте изменим экземпляр начального набора, добавив к нему такое же значение:

set.add("Costa Rica");

Таким образом, мы косвенно изменим неизменяемый набор. Итак, когда мы печатаем экземпляр немодифицируемого набора:

[Canada, USA, Costa Rica]

Как мы видим, элемент «Коста-Рика» также присутствует в немодифицируемом наборе.

4. Создание неизменяемых наборов в Java 9

Начиная с Java 9 для создания неизменяемых наборов доступен статический фабричный метод Set.of(elements):

Set<String> immutable = Set.of("Canada", "USA");

5. Создание неизменяемых наборов в Guava ~~ ~ Другой способ создания неизменяемого набора — использование класса ImmutableSet в Guava. Он копирует существующие данные в новый неизменяемый экземпляр. В результате данные внутри ImmutableSet не изменятся, когда мы изменим исходный набор.

Как и в базовой реализации Java, любая попытка изменить созданный неизменяемый экземпляр вызовет исключение UnsupportedOperationException.

Теперь давайте рассмотрим различные способы создания неизменяемых экземпляров.

5.1. Использование ImmutableSet.copyOf()

Проще говоря, метод ImmutableSet.copyOf() возвращает копию всех элементов в наборе:

Таким образом, после изменения исходного набора неизменяемый экземпляр останется то же:

Set<String> immutable = ImmutableSet.copyOf(set);

5.2. Использование ImmutableSet.of()

[Canada, USA]

Аналогично, с помощью метода ImmutableSet.of() мы можем мгновенно создать неизменяемый набор с заданными значениями:

Когда мы не указываем никаких элементов, ImmutableSet.of () вернет пустой неизменяемый набор.

Set<String> immutable = ImmutableSet.of("Canada", "USA");

Это можно сравнить с Set.of() в Java 9.

6. Заключение

В этой быстрой статье мы обсудили неизменяемые множества в языке Java. Кроме того, мы показали, как создавать неизменяемые наборы с помощью API коллекций из ядра Java, Java 9 и библиотеки Guava.

Наконец, как обычно, полный код этой статьи доступен на GitHub.

«