1. Знайомство з CollectionUtils

Ще один універсальний утилітний клас, який містить багато корисних методів:

addAll(Collection<C> collection, C... elements) Додає всі елементи масиву C до колекції
addIgnoreNull(Collection<T> collection, T object) Додає елемент, якщо він не null
containsAll(Collection<?>coll1, Collection<?>coll2) Перевіряє, що колекція1 містить усі елементи колекції2
containsAny(Collection<?>coll1, Collection<?>coll2) Перевіряє, що колекція1 містить хоча б один елемент із колекції2
countMatches(Iterable<C> input, Predicate<? super C> predicate) Підраховує, скільки елементів колекції задовільняють правилу.
disjunction(Iterable<? extends O> a, Iterable<? extends O> b) Повертає об'єкти, які входять лише до однї колекції, але не одразу до обидвох
intersection(Iterable<? extends O> a, Iterable<? extends O> b) Повертає колекцію об'єктів, які входять одразу до обох колекцій
union(Iterable<? extends O> a, Iterable<? extends O> b) Повертає колекцію об'єктів, які входять хоча б до однієї колекції
emptyCollection() Повертає спеціальну порожню колекцію
emptyIfNull(Collection<T> collection) Повертає порожню колекцію, якщо collection == null
exists(Iterable<C> input, Predicate<? super C> predicate) Перевіряє, що у колекції існує елемент, що задовільняє правилу.
extractSingleton(Collection<E> collection) Повертає єдиний елемент колекції
filter(Iterable<T> collection, Predicate<? super T> predicate) Фільтрує елементи колекції
find(Iterable<T> collection, Predicate<? super T> predicate) Шукає елементи колекції
isEmpty(Collection<?> coll) Перевіряє, що колекція порожня
isEqualCollection(Collection<?> a, Collection<?> b) Порівнює колекції
isFull(Collection<? extends Object> coll) Перевіряє, чи можна ще додати елемент до колекції
isNotEmpty(Collection<?> coll) Перевіряє, що колекція не пуста
isSubCollection(Collection<?> a, Collection<?> b) Перевіряє, що колекція B входить до колекції A
matchAll(Iterable<C> input, Predicate<? super C> predicate) Перевіряє, що всі елементи колекції задовільняють правилу.
removeAll(Collection<E> collection, Collection<?> remove) Видаляє всі елементи колекції
retainAll(Collection<C> collection, Collection<?> retain) Повертає колекцію, що містить всі елементи collection, які також містяться в retain
reverseArray(Object[] array) Розвертає масив задом наперед
unmodifiableCollection(Collection<? extends C> collection) Повертає обгортку над колекцією. Будь-яка спроба модифікувати колекцію кине виняток.

Розглянемо деякі методи.

2. Способи перевірки, чи порожня колекція

Ось як просто визначити, чи колекція є порожньою:


CollectionUtils.isEmpty(null); // true
CollectionUtils.isEmpty(new LinkedList<>()); // true  
CollectionUtils.isEmpty(Collections.singleton(new int[]{2, 1})); // false

Також легко перевірити, що колекція не порожня:


CollectionUtils.isNotEmpty(null); // false
CollectionUtils.isNotEmpty(new LinkedList<>()); // false  
CollectionUtils.isNotEmpty(Collections.singleton(new int[]{2, 1})); // true

Приклади:


User ivan = new User("Ivan", "ivan@email.com");
User petr = new User("Petr", "petr@email.com");

List<User> users = new ArrayList<>();

System.out.println(CollectionUtils.isEmpty(users)); // true
System.out.println(CollectionUtils.isNotEmpty(users)); // false

users.add(ivan);
users.add(petr);

System.out.println(CollectionUtils.isEmpty(users)); // false
System.out.println(CollectionUtils.isNotEmpty(users)); // true

users = null;
System.out.println(CollectionUtils.isEmpty(users)); // true
System.out.println(CollectionUtils.isNotEmpty(users)); // false

A Guide to Apache Commons Collections CollectionUtils

3. Операції над множинами

Якщо тобі доводилося стикатися з теорією множин, ти знаєш, що над множинами існують 4 основні операції: об'єднання, перетин, різниця та диз'юнкція.

Для цих операцій у класу CollectionUtils є 4 методи:

  • union()
  • intersection()
  • disjunction()
  • subtract()

Нижче буде кілька простих прикладів:

Об'єднання


List<String> firstList = Arrays.asList("1", "2", "3", "4", "5", "6");
List<String> secondList = Arrays.asList("2", "3", "6", "7", "8", "9");

//об'єднуємо дві множини
Collection<String> result = CollectionUtils.union(firstList, secondList);
System.out.println(ArrayUtils.toString(result));     //[1, 2, 3, 4, 5, 6, 7, 8, 9]

Перетин


List<String> firstList = Arrays.asList("A", "B", "C", "D", "E", "F");
List<String> secondList = Arrays.asList("B", "D", "F", "G", "H", "K");

//перетин двох множин
Collection<String> result = CollectionUtils.intersection(firstList, secondList);
System.out.println(ArrayUtils.toString(result));     //[B, D, F]

Диз'юнкція


List<String> firstList = Arrays.asList("1", "2", "3", "4", "5", "6");
List<String> secondList = Arrays.asList("2", "3", "6", "7", "8", "9");

//диз'юнкція
Collection<String> result = CollectionUtils.disjunction(firstList, secondList);
System.out.println(ArrayUtils.toString(result)); //[1, 4, 5, 7, 8, 9]

Різниця (відрахування)


List<String> firstList = Arrays.asList("1", "2", "3", "4", "5", "6");
List<String> secondList = Arrays.asList("2", "3", "6", "7", "8", "9");

//різниця
Collection<String> result = CollectionUtils.subtract(firstList, secondList);
System.out.println(ArrayUtils.toString(result)); // [1, 4, 5]

4. Операції над множинами, продовження

У цьому прикладі показано, як використовувати ці чотири методи для роботи з двома колекціями:


List<Integer> firstList = Arrays.asList(1, 2, 3, 3, 4, 5);
List<Integer> secondList = Arrays.asList(3, 4, 4, 5, 6, 7);

Collection<Integer> union = CollectionUtils.union(firstList, secondList); // Об'єднання
Collection<Integer> intersection = CollectionUtils.intersection(firstList, secondList); // Перетин
Collection<Integer> disjunction = CollectionUtils.disjunction(firstList, secondList); // Диз'юнкція
Collection<Integer> subtract = CollectionUtils.subtract(firstList, secondList); // Різниця

System.out.println("firstList: " + ArrayUtils.toString(firstList.toArray()));
System.out.println("secondList: " + ArrayUtils.toString(secondList.toArray()));

System.out.println("Объединение: " + ArrayUtils.toString(union.toArray()));
System.out.println("Пересечение: " + ArrayUtils.toString(intersection.toArray()));
System.out.println("Дизъюнкция: " + ArrayUtils.toString(disjunction.toArray()));
System.out.println("Разница: " + ArrayUtils.toString(subtract.toArray()));

Наш результат:

firstList: {1,2,3,3,4,5}
secondList: {3,4,4,5,6,7}
Об'єднання: {1,2,3,3,4,4,5,6,7}
Перетин: {3,4,5}
Диз'юнкція: {1,2,3,4,6,7}
Різниця: {1,2,3}

Можеш самостійно поекспериментувати з цими методами.

5. Метод unmodifiableCollection()

Іноді доводиться реалізовувати методи інтерфейсу, які мають повертати колекції внутрішніх даних наших об'єктів. Оскільки дані внутрішні, ми не хочемо, щоб хтось десь їх змінював.

Або ми отримали десь колекцію, яку не потрібно змінювати, але змушені передати її до якогось стороннього методу. Де гарантія, що він її не змінить?

Щоб спати спокійно, колекцію можна огорнути в спеціальний wrapper, який кидатиме виняток при спробі модифікувати колекцію.

Приклад:


Collection<String> firstCollection = new ArrayList<String>();
Collection<String> secondCollection = Collections.unmodifiableCollection(firstCollection);
firstCollection.add("hello");
firstCollection.add("from");
firstCollection.add("javaRush");

//secondCollection.add("have a error");
System.out.println(secondCollection); //[hello, from, javaRush]

Метод Collections.unmodifiableCollection() повертає обгортку над колекцією, яка передалася. Якщо викликати в неї методи get(), size(), все буде працювати. Проте в разі виклику методів add(), set(), remove() ти отримаєш виняток.

java.lang.UnsupportedOperationException
at org.apache.commons.collections.collection.UnmodifiableCollection.add(UnmodifiableCollection.java:75)

Насправді вже зараз метод позначено як deprecated і замість нього рекомендується використовувати Collections.unmodifiableCollection (Collection <? extends T> c).


Collection<String> firstCollection = new ArrayList<String>();
Collection<String> secondCollection =
Collections.unmodifiableCollection(firstCollection);