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

Руководство по коллекциям Apache Commons

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

1. Обзор

Проще говоря, Apache CollectionUtils предоставляет служебные методы для общих операций, которые охватывают широкий спектр вариантов использования и помогают избежать написания шаблонного кода. Библиотека предназначена для более старых выпусков JVM, поскольку в настоящее время аналогичная функциональность предоставляется Stream API Java 8.

2. Зависимости Maven

Нам нужно добавить следующую зависимость, чтобы начать работу с CollectionUtils:

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>

Последнюю версию библиотеки можно найти здесь .

3. Настройка

Добавим классы Customer и Address:

public class Customer {
private Integer id;
private String name;
private Address address;

// standard getters and setters
}

public class Address {
private String locality;
private String city;

// standard getters and setters
}

Мы также будем держать под рукой следующие экземпляры Customer и List , готовые для тестирования нашей реализации:

Customer customer1 = new Customer(1, "Daniel", "locality1", "city1");
Customer customer2 = new Customer(2, "Fredrik", "locality2", "city2");
Customer customer3 = new Customer(3, "Kyle", "locality3", "city3");
Customer customer4 = new Customer(4, "Bob", "locality4", "city4");
Customer customer5 = new Customer(5, "Cat", "locality5", "city5");
Customer customer6 = new Customer(6, "John", "locality6", "city6");

List<Customer> list1 = Arrays.asList(customer1, customer2, customer3);
List<Customer> list2 = Arrays.asList(customer4, customer5, customer6);
List<Customer> list3 = Arrays.asList(customer1, customer2);

List<Customer> linkedList1 = new LinkedList<>(list1);

4. КоллекцияUtils

Давайте рассмотрим некоторые из наиболее часто используемых методов в классе Apache Commons CollectionUtils .

4.1. Добавление только ненулевых элементов

Мы можем использовать метод addIgnoreNull из CollectionUtils, чтобы добавить в предоставленную коллекцию только ненулевые элементы.

Первый аргумент этого метода — это коллекция, в которую мы хотим добавить элемент, а второй аргумент — это элемент, который мы хотим добавить:

@Test
public void givenList_whenAddIgnoreNull_thenNoNullAdded() {
CollectionUtils.addIgnoreNull(list1, null);

assertFalse(list1.contains(null));
}

Обратите внимание, что нуль не был добавлен в список.

4.2. Сортировка списков

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

@Test
public void givenTwoSortedLists_whenCollated_thenSorted() {
List<Customer> sortedList = CollectionUtils.collate(list1, list2);

assertEquals(6, sortedList.size());
assertTrue(sortedList.get(0).getName().equals("Bob"));
assertTrue(sortedList.get(2).getName().equals("Daniel"));
}

4.3. Преобразование объектов

Мы можем использовать метод преобразования для преобразования объектов класса А в различные объекты класса В. Этот метод принимает в качестве аргументов список объектов класса А и преобразователь .

Результатом этой операции является список объектов класса B:

@Test
public void givenListOfCustomers_whenTransformed_thenListOfAddress() {
Collection<Address> addressCol = CollectionUtils.collect(list1,
new Transformer<Customer, Address>() {
public Address transform(Customer customer) {
return customer.getAddress();
}
});

List<Address> addressList = new ArrayList<>(addressCol);
assertTrue(addressList.size() == 3);
assertTrue(addressList.get(0).getLocality().equals("locality1"));
}

4.4. Фильтрация объектов

С помощью фильтра мы можем удалить из списка объекты, которые не удовлетворяют заданному условию . Метод принимает список в качестве первого аргумента и предикат в качестве второго аргумента.

Метод filterInverse делает обратное. Он удаляет объекты из списка, когда Predicate возвращает значение true.

И filter , и filterInverse возвращают true , если входной список был изменен, т. е. хотя бы один объект был отфильтрован из списка:

@Test
public void givenCustomerList_WhenFiltered_thenCorrectSize() {

boolean isModified = CollectionUtils.filter(linkedList1,
new Predicate<Customer>() {
public boolean evaluate(Customer customer) {
return Arrays.asList("Daniel","Kyle").contains(customer.getName());
}
});

assertTrue(linkedList1.size() == 2);
}

Мы можем использовать select и selectRejected , если хотим, чтобы возвращался результирующий список, а не логический флаг.

4.5. Проверка на непустое

Метод isNotEmpty очень удобен, когда мы хотим проверить, есть ли в списке хотя бы один элемент. Другой способ проверить то же самое:

boolean isNotEmpty = (list != null && list.size() > 0);

Хотя приведенная выше строка кода делает то же самое, CollectionUtils.isNotEmpty делает наш код чище:

@Test
public void givenNonEmptyList_whenCheckedIsNotEmpty_thenTrue() {
assertTrue(CollectionUtils.isNotEmpty(list1));
}

isEmpty делает обратное. Он проверяет, является ли данный список нулевым или в списке нет элементов:

List<Customer> emptyList = new ArrayList<>();
List<Customer> nullList = null;

assertTrue(CollectionUtils.isEmpty(nullList));
assertTrue(CollectionUtils.isEmpty(emptyList));

4.6. Проверка включения

Мы можем использовать isSubCollection , чтобы проверить, содержится ли коллекция в другой коллекции. isSubCollection принимает две коллекции в качестве аргументов и возвращает true , если первая коллекция является подколлекцией второй коллекции:

@Test
public void givenCustomerListAndASubcollection_whenChecked_thenTrue() {
assertTrue(CollectionUtils.isSubCollection(list3, list1));
}

Коллекция является подколлекцией другой коллекции, если количество раз, когда объект встречается в первой коллекции, меньше или равно количеству раз, которое он встречается во второй коллекции.

4.7. Пересечение коллекций

Мы можем использовать метод CollectionUtils.intersection , чтобы получить пересечение двух коллекций. Этот метод принимает две коллекции и возвращает коллекцию элементов, которые являются общими для обеих входных коллекций:

@Test
public void givenTwoLists_whenIntersected_thenCheckSize() {
Collection<Customer> intersection = CollectionUtils.intersection(list1, list3);
assertTrue(intersection.size() == 2);
}

Количество раз, когда элемент встречается в результирующей коллекции, равно минимальному количеству раз, когда он встречается в каждой из заданных коллекций.

4.8. Вычитание коллекций

CollectionUtils.subtract принимает на вход две коллекции и возвращает коллекцию, содержащую элементы, которые есть в первой коллекции, но отсутствуют во второй коллекции:

@Test
public void givenTwoLists_whenSubtracted_thenCheckElementNotPresentInA() {
Collection<Customer> result = CollectionUtils.subtract(list1, list3);
assertFalse(result.contains(customer1));
}

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

4.9. Союз коллекций

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

@Test
public void givenTwoLists_whenUnioned_thenCheckElementPresentInResult() {
Collection<Customer> union = CollectionUtils.union(list1, list2);

assertTrue(union.contains(customer1));
assertTrue(union.contains(customer4));
}

Количество раз, когда элемент встречается в результирующей коллекции, равно максимальному количеству раз, когда он встречается в каждой из заданных коллекций.

5. Вывод

И мы закончили.

Мы рассмотрели некоторые из часто используемых методов CollectionUtils , которые очень полезны, чтобы избежать шаблонов при работе с коллекциями в наших проектах Java.

Как обычно, код доступен на GitHub.