Перейти к основному содержимому

Неизменяемый набор в Java

· 3 мин. чтения

1. Введение

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

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

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

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

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

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

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

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

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

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

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

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

Далее, давайте закончим с Collections . немодифицируемый набор():

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

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

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

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

Как мы ожидаем, тест пройдет успешно. Кроме того, операция add() запрещена для немодифицируемого экземпляра Set и вызовет исключение 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 не изменятся, когда мы изменим исходный Set .

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

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

5.1. Использование неизменяемого набора. копия()

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

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

Итак, после изменения начального набора неизменяемый экземпляр останется прежним:

[Canada, USA]

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

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

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

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

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

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

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

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