«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. CollectionUtils ~~ ~ Давайте рассмотрим некоторые из наиболее часто используемых методов класса Apache Commons CollectionUtils.

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

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

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

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

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

4.2. Сопоставление списков

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

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

@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"));
}

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

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

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

@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"));
}

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

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

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

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

@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);
}

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

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

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

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

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

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

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

List<Customer> emptyList = new ArrayList<>();
List<Customer> nullList = null;
 
assertTrue(CollectionUtils.isEmpty(nullList));
assertTrue(CollectionUtils.isEmpty(emptyList));

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

«

As usual, the code is available over on GitHub.

Next »

Apache Commons Collections MapUtils

« Previous

Apache Commons Collections BidiMap