Коллекции Apache Commons SetUtils

Коллекции Apache Commons SetUtils

1. обзор

В этой статье мы исследуем APISetUtils библиотеки Apache Commons Collections. Проще говоря, эти утилиты можно использовать для выполнения определенных операций со структурами данныхSet в Java.

2. Установка зависимости

Чтобы использовать библиотекуSetUtils в нашем проекте, нам нужно добавить следующую зависимость в файлpom.xml нашего проекта:


    org.apache.commons
    commons-collections4
    4.1

В качестве альтернативы, если наш проект основан на Gradle, мы должны добавить зависимость в файлbuild.gradle нашего проекта. Также нам нужно добавитьmavenCentral() в раздел репозиториев файлаbuild.gradle:

compile 'org.apache.commons:commons-collections4:4.1'

3. Предварительный набор

МетодpredicatedSet() библиотекиSetUtils позволяет определять условия, которым должны соответствовать все элементы, которые должны быть вставлены в набор. Он принимает исходный объектSet и предикат.

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

Если проверка не удалась для любого элемента, будет брошенIllegalArgumentException. Фрагмент нижеprevents the addition ofstrings that do not start with ‘L' вsourceSet или возвращаемыйvalidatingSet:

Set validatingSet
  = SetUtils.predicatedSet(sourceSet, s -> s.startsWith("L"));

В библиотеке также естьpredicatedSortedSet() иpredicatedNavigableSet() для работы сSortedSet иNavigableSet соответственно.

4. Объединение, различие и пересечение множества

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

Методdifference() принимает два объектаSet и возвращает неизменяемый объектSetUtils.SetView. ВозвращенныйSetUtils.SetView содержит элементы, которые находятся в набореa, но не входят в наборb:

Set a = new HashSet<>(Arrays.asList(1, 2, 5));
Set b = new HashSet<>(Arrays.asList(1, 2));
SetUtils.SetView result = SetUtils.difference(a, b);

assertTrue(result.size() == 1 && result.contains(5));

Отметим, чтоtrying to perform write operations, like add() or addAll(), on the returned SetUtils.SetView will throw an UnsupportedOperationException.

Чтобы изменить возвращаемый результат, нам нужно вызвать методtoSet() возвращенногоSetUtils.SetView, чтобы получить доступный для записи объектSet:

Set mutableSet = result.toSet();

Методunion библиотекиSetUtils делает именно то, что он звучит, - он возвращает все элементы набораa иb. Методunion также возвращает неизменяемый объектSetUtil.SetView:

Set expected = new HashSet<>(Arrays.asList(1, 2, 5));
SetUtils.SetView union = SetUtils.union(a, b);

assertTrue(SetUtils.isEqualSet(expected, union));

Take note of the isEqualSet() method используется в заявлении assert. Это удобный статический метод библиотекиSetUtils, который эффективно проверяет, равны ли два набора.

Чтобы получить пересечение множества, т.е. элементы, которые присутствуют как в набореa, так и в набореb, мы будем использовать методSetUtils.intersection(). Этот метод также возвращает объектSetUtil.SetView:

Set expected = new HashSet<>(Arrays.asList(1, 2));
SetUtils.SetView intersect = SetUtils.intersection(a, b);

assertTrue(SetUtils.isEqualSet(expected, intersect));

5. Преобразование элементов набора

Давайте взглянем на еще один интересный метод -SetUtils.transformedSet(). Этот метод принимает объектSet и интерфейсTransformer. При поддержке исходного набора он использует методtransform() интерфейсаTransformer для преобразования каждого элемента набора.

Логика преобразования определена в методеtransform() интерфейсаTransformer, который применяется к каждому элементу, добавленному в набор. Фрагмент кода ниже умножает каждый элемент, добавленный к набору, на 2:

Set a = SetUtils.transformedSet(new HashSet<>(), e -> e * 2  );
a.add(2);

assertEquals(a.toArray()[0], 4);

МетодtransformedSet() довольно удобен - их можно даже использовать для приведения элементов набора - скажем, из String в Integer. Просто убедитесь, что тип вывода является подтипом ввода.

Допустим, мы работаем сSortedSet илиNavigableSet вместоHashSet,, мы можем использоватьtransformedSortedSet() илиtransformedNavigableSet() соответственно.

Обратите внимание, что новый экземплярHashSet передается методуtransformedSet(). В ситуациях, когда существующий непустойSet передается методу, уже существующие элементы не будут преобразованы.

Если мы хотим преобразовать уже существующие элементы (и те, которые были добавлены впоследствии), нам нужно использовать методtransformedSet() дляorg.apache.commons.collections4.set.TransformedSet:

Set source = new HashSet<>(Arrays.asList(1));
Set newSet = TransformedSet.transformedSet(source, e -> e * 2);

assertEquals(newSet.toArray()[0], 2);
assertEquals(source.toArray()[0], 2);

Обратите внимание, что элементы из исходного набора преобразуются, а результат копируется в возвращенныйnewSet.

6. Установить дизъюнкцию

БиблиотекаSetUtils предоставляет статический метод, который можно использовать для поиска заданных дизъюнкций. Дизъюнкция набораa и набораb - это все элементы, которые уникальны для набора a и набора b.

Давайте посмотрим, как использовать методdisjunction() библиотекиSetUtils:

Set a = new HashSet<>(Arrays.asList(1, 2, 5));
Set b = new HashSet<>(Arrays.asList(1, 2, 3));
SetUtils.SetView result = SetUtils.disjunction(a, b);

assertTrue(
  result.toSet().contains(5) && result.toSet().contains(3));

7. Другие методы в библиотекеSetUtils

В библиотекеSetUtils есть и другие методы, упрощающие обработку заданных данных:

  • Мы можем использоватьsynchronizedSet() илиsynchronizedSortedSet(), чтобы получить потокобезопасныйSet. Однако, как указано в документации, мыmust manually synchronize итератор возвращенного набора, чтобы избежать недетерминированного поведения

  • Мы можем использоватьSetUtils.unmodifiableSet(), чтобы получить набор только для чтения. Обратите внимание, что попытка добавить элементы к возвращенному объектуSet выдастUnsupportedOperationException

  • Существует также методSetUtils.emptySet(), который возвращает типобезопасный неизменяемый пустой набор

  • МетодSetUtils.emptyIfNull() принимает объектSet, допускающий значение NULL. Он возвращает пустой, доступный только для чтения, Set, если предоставленныйSet равен нулю; в противном случае он возвращает предоставленныйSet

  • SetUtils.orderedSet() вернет объектSet, который поддерживает порядок добавления элементов.

  • SetUtils.hashCodeForSet() может сгенерировать хэш-код для набора - таким образом, что два набора одинаковых элементов будут иметь один и тот же хэш-код

  • SetUtils.newIdentityHashSet() вернетHashSet, который использует== для сопоставления элемента вместо методаequals(). Прочтите о его предостереженияхhere

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

В этой статье мы подробно разобрались с библиотекойSetUtils. Служебный класс предлагает статические методы, которые делают работу с заданной структурой данных простой и увлекательной. Это также повышает производительность.

Как всегда доступны фрагменты кодаover on GitHub. Официальный документ для APISetUtils может бытьfound here.