«1. Обзор

Проще говоря, набор — это набор, не содержащий повторяющихся элементов. В Java Set — это интерфейс, расширяющий интерфейс Collection.

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

2. Конструктор копирования

Одним из способов копирования Set является использование конструктора копирования реализации Set:

Set<T> copy = new HashSet<>(original);

Конструктор копирования — это специальный тип конструктора, который используется для создания нового объекта. путем копирования существующего объекта.

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

3. Set.addAll

Интерфейс Set имеет метод addAll. Он добавляет элементы коллекции в целевой набор. Следовательно, мы можем использовать метод addAll для копирования элементов существующего набора в пустой набор:

Set<T> copy = new HashSet<>();
copy.addAll(original);

4. Set.clone

Не будем забывать, что Set — это интерфейс, расширяющий интерфейс Collection поэтому нам нужно обратиться к объекту, который реализует интерфейс Set, чтобы создать еще один экземпляр Set. HashSet, TreeSet, LinkedHashSet и EnumSet — все это примеры реализации Set в Java.

Все эти реализации Set имеют метод clone, так как все они реализуют интерфейс Cloneable.

Итак, в качестве другого подхода к копированию набора мы можем вызвать метод clone набора:

Set<T> copy = (Set<T>) original.clone();

Отметим также, что клонирование исходно происходит из Object.clone. Реализации набора переопределяют метод клонирования класса Object. Характер клона зависит от фактической реализации. Например, HashSet делает только поверхностную копию, хотя мы можем запрограммировать способ сделать глубокую копию.

Как мы видим, мы вынуждены привести клонированный объект к типу Set\u003cT\u003e, так как метод clone на самом деле возвращает объект.

5. JSON

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

В этом примере мы скопируем набор, используя методы сериализации и десериализации библиотеки Google Gson:

Gson gson = new Gson();
String jsonStr = gson.toJson(original);
Set<T> copy = gson.fromJson(jsonStr, Set.class);

6. Apache Commons Lang

В Apache Commons Lang есть класс SerializationUtils, который предоставляет специальный метод — clone — который можно использовать для клонирования данного объекта. Мы можем использовать этот метод для копирования набора:

for (T item : original) {
    copy.add(SerializationUtils.clone(item));
}

Обратите внимание, что SerializationUtils.clone ожидает, что его параметр будет расширять класс Serializable.

7. Collectors.toSet

Или мы можем использовать Stream API Java 8 с Collectors для клонирования набора:

Set<T> copy = original.stream()
    .collect(Collectors.toSet());

Одним из преимуществ Stream API является то, что он обеспечивает больше удобства, позволяя нам использовать пропуски, фильтры и многое другое.

8. Использование Java 10

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

Set<T> copy = Set.copyOf(original);

Обратите внимание, что Set.copyOf ожидает ненулевой параметр.

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

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

Как всегда, ознакомьтесь с исходным кодом наших примеров, включая код для Java 10.