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.