1. Обзор
В этой статье мы рассмотрим API SetUtils
библиотеки Apache Commons Collections. Проще говоря, эти утилиты можно использовать для выполнения определенных операций над структурами данных Set
в Java.
2. Установка зависимостей
Чтобы мы могли использовать библиотеку SetUtils
в нашем проекте, нам нужно добавить следующую зависимость в файл pom.xml
нашего проекта :
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
В качестве альтернативы, если наш проект основан на Gradle, мы должны добавить зависимость в файл build.gradle нашего проекта.
Также нам нужно добавить mavenCentral()
в раздел репозиториев файла build.gradle
:
compile 'org.apache.commons:commons-collections4:4.1'
3. Предикативный набор
Метод predicatedSet()
библиотеки SetUtils
позволяет определить условия, которым должны удовлетворять все элементы, вставляемые в набор. Он принимает исходный объект Set
и предикат.
Мы можем использовать это, чтобы легко проверить, что все элементы набора
удовлетворяют определенному условию, что может быть удобно при разработке сторонней библиотеки/API.
Если проверка не пройдена для любого элемента, будет выдано исключение IllegalArgumentException
. Фрагмент ниже предотвращает добавление строк, которые не начинаются с «L», в исходный набор
или возвращаемый набор проверки
:
Set<String> validatingSet
= SetUtils.predicatedSet(sourceSet, s -> s.startsWith("L"));
В библиотеке также есть функции predicatedSortedSet()
и predicatedNavigableSet()
для работы с SortedSet
и NavigableSet
соответственно.
4. Объединение, разность и пересечение множества.
В библиотеке есть методы, которые могут вычислять объединение, разность и пересечение элементов Set
.
Метод разница()
принимает два объекта Set
и возвращает неизменяемый SetUtils.
Объект SetView
. Возвращенный SetUtils.
SetView
содержит элементы, которые есть в наборе a,
но не в наборе b
:
Set<Integer> a = new HashSet<>(Arrays.asList(1, 2, 5));
Set<Integer> b = new HashSet<>(Arrays.asList(1, 2));
SetUtils.SetView<Integer> result = SetUtils.difference(a, b);
assertTrue(result.size() == 1 && result.contains(5));
Обратите внимание, что при попытке выполнить операции записи, такие как add()
или addAll()
, для возвращенных SetUtils.
SetView
вызовет исключение UnsupportedOperationException
.
Чтобы изменить возвращенный результат, нам нужно вызвать метод toSet()
возвращенного SetUtils.
SetView
для получения доступного для записи объекта Set :
Set<Integer> mutableSet = result.toSet();
Метод union
библиотеки SetUtils
делает именно то, на что он похож — он возвращает все элементы набора a
и b
. Метод union
также возвращает неизменяемый объект SetUtil.SetView :
Set<Integer> expected = new HashSet<>(Arrays.asList(1, 2, 5));
SetUtils.SetView<Integer> union = SetUtils.union(a, b);
assertTrue(SetUtils.isEqualSet(expected, union));
Обратите внимание на метод isEqualSet ()
, используемый в операторе assert. Это удобный статический метод библиотеки SetUtils
, эффективно проверяющий, равны ли два множества.
Чтобы получить пересечение набора, т. е. элементы, которые присутствуют как в наборе a,
так и в наборе b
, мы будем использовать SetUtils.
Метод пересечения() .
Этот метод также возвращает объект SetUtil.SetView
:
Set<Integer> expected = new HashSet<>(Arrays.asList(1, 2));
SetUtils.SetView<Integer> intersect = SetUtils.intersection(a, b);
assertTrue(SetUtils.isEqualSet(expected, intersect));
5. Преобразование элементов набора
Давайте рассмотрим еще один интересный метод — SetUtils.
преобразованный набор()
. Этот метод принимает объект Set
и интерфейс Transformer .
Опираясь на исходный набор, он использует метод transform () интерфейса
Transformer
для преобразования каждого элемента набора.
Логика преобразования определяется в методе transform() интерфейса
Transformer
, который применяется к каждому элементу, добавляемому в набор. Фрагмент кода ниже умножает каждый элемент, добавленный в набор, на 2:
Set<Integer> a = SetUtils.transformedSet(new HashSet<>(), e -> e * 2 );
a.add(2);
assertEquals(a.toArray()[0], 4);
Метод transformSet()
очень удобен — его можно даже использовать для приведения элементов набора — скажем, из String в Integer. Просто убедитесь, что тип вывода является подтипом ввода.
Предположим, что мы работаем с SortedSet
или NavigableSet
вместо HashSet,
мы можем использовать transformedSortedSet()
или convertNavigableSet ()
соответственно.
Обратите внимание, что новый экземпляр HashSet
передается в метод transformSet()
. В ситуациях, когда существующий непустой набор
передается методу, ранее существовавшие элементы не будут преобразованы.
Если мы хотим преобразовать уже существующие элементы (и добавленные впоследствии), нам нужно использовать метод transformSet()
из org.apache.commons.collections4.set.TransformedSet
:
Set<Integer> source = new HashSet<>(Arrays.asList(1));
Set<Integer> newSet = TransformedSet.transformedSet(source, e -> e * 2);
assertEquals(newSet.toArray()[0], 2);
assertEquals(source.toArray()[0], 2);
Обратите внимание, что элементы из исходного набора преобразуются, а результат копируется в возвращаемый новый набор.
6. Установите дизъюнкцию
Библиотека SetUtils
предоставляет статический метод, который можно использовать для поиска дизъюнкций множеств. Дизъюнкция множества a
и множества b
— это все элементы, которые уникальны для множества a и множества b.
Давайте посмотрим, как использовать метод disjunction () библиотеки
SetUtils
:
Set<Integer> a = new HashSet<>(Arrays.asList(1, 2, 5));
Set<Integer> b = new HashSet<>(Arrays.asList(1, 2, 3));
SetUtils.SetView<Integer> result = SetUtils.disjunction(a, b);
assertTrue(
result.toSet().contains(5) && result.toSet().contains(3));
7. Другие методы в библиотеке SetUtils
В библиотеке SetUtils есть и другие методы, упрощающие обработку заданных данных:
- Мы можем использовать
synchronizedSet()
илиsynchronizedSortedSet()
, чтобы получить потокобезопасныйSet
. Однако, как указано в документах, мы должны вручную синхронизировать итератор возвращаемого набора, чтобы избежать недетерминированного поведения. - Мы можем использовать
SetUtils.unmodifiedSet()
, чтобы получить набор только для чтения. Обратите внимание, что попытка добавить элементы в возвращаемый объектSet вызовет
исключение UnsupportedOperationException .
- Существует также метод
SetUtils.emptySet()
, который возвращает типобезопасный неизменяемый пустой набор. - Метод
SetUtils.emptyIfNull()
принимает объектSet
, допускающий значение NULL . Он возвращает пустой набор, доступный только для чтения, если предоставленныйнабор
имеет
значение null; в противном случае он возвращает предоставленныйSet
SetUtils.orderedSet()
вернет объектSet
, который поддерживает порядок добавления элементов.SetUtils.hashCodeForSet()
может генерировать хэш-код для набора таким образом, что два набора одинаковых элементов будут иметь одинаковый хэш-код.SetUtils.newIdentityHashSet()
вернетHashSet
, который использует==
для сопоставления элемента вместо методаequals()
. Пожалуйста, прочитайте о его предостережениях здесь
8. Заключение
В этой статье мы подробно изучили библиотеку SetUtils
. Вспомогательный класс предлагает статические методы, которые делают работу с установленной структурой данных простой и увлекательной. Это также повышает производительность.
Как всегда, фрагменты кода доступны на GitHub . Официальный документ по SetUtils
API можно найти здесь .