Поєднання різних типів колекцій на Java

1. Вступ

У цьому короткому посібнику ми дослідимо різні способи поєднання колекцій на Java.

Ми вивчимо різні підходи з використанням Java та зовнішніх фреймворків, таких як Guava, Apache тощо. Для ознайомлення з колекціями подивіться на цю серію тут.

2. Зовнішні бібліотеки для роботи з колекціями

Поряд із власними підходами, ми також будемо використовувати зовнішні бібліотеки. Будь ласка, додайте такі залежності в pom.xml :

 org.apache.commons commons-collections4 4.2   org.apache.commons commons-exec 1.3   com.google.guava guava 26.0-jre 

Найновіші версії можна знайти на Maven Central для Commons, Commons-exec та Guava.

3. Поєднання масивів у Java

3.1. Рідне рішення Java

Java постачається із вбудованим методом void arraycopy (), який копіює заданий вихідний масив до цільового.

Ми можемо використовувати його наступним чином:

Object[] combined = new Object[first.length + second.length]; System.arraycopy(first, 0, combined, 0, first.length); System.arraycopy(second, 0, combined, first.length, second.length);

У цьому методі, поряд з об'єктами масиву, ми також вказуємо позицію, звідки нам потрібно скопіювати, а також передаємо параметр length.

Це власне рішення Java, тому для нього не потрібні зовнішні бібліотеки.

3.2. Використання Java 8 Stream API

Потоки пропонують ефективний спосіб перегляду кількох різних типів колекцій. Щоб розпочати роботу з потоками, перейдіть до підручника API 8 Stream API.

Щоб об’єднати масиви за допомогою Stream , ми можемо використовувати такий код:

Object[] combined = Stream.concat(Arrays.stream(first), Arrays.stream(second)).toArray();

Stream.concat () створює об'єднаний потік, в якому за елементами першого потоку слідують елементи другого потоку, який після цього перетворюється в масив за допомогою методу toArray () .

Процес створення потоку однаковий для різних типів колекцій. Однак ми можемо збирати його різними способами, щоб отримати з нього різні структури даних.

Ми переглянемо цей метод у розділах 4.2. та 5.2. щоб побачити, як ми можемо використовувати той самий метод у списках та наборах .

3.3. Використання ArrayUtils від Apache Commons

Спільна бібліотека Apache надає нам метод addAll () із пакету ArrayUtils . Ми можемо вказати цільовий та вихідний масив як параметри, і цей метод поверне комбінований масив:

Object[] combined = ArrayUtils.addAll(first, second);

Цей метод також детально обговорюється в статті «Обробка масиву за допомогою Apache Commons Lang 3».

3.4. Використання гуави

Guava надає нам метод concat () з тією ж метою:

Object [] combined = ObjectArrays.concat(first, second, Object.class);

Його можна використовувати з різними типами даних, і він приймає два вихідні масиви разом із літералом класу для повернення комбінованого масиву.

4. Об’єднання списку в Java

4.1. Використання колекції Native addAll () Метод

Сам інтерфейс Collection надає нам метод addAll () , який додає всі елементи вказаної колекції до об'єкта, що викликає. Це також детально обговорюється в цій статті Baeldung:

List combined = new ArrayList(); combined.addAll(first); combined.addAll(second);

Оскільки цей метод надається в самому батьківському інтерфейсі фреймворку Collections, тобто в інтерфейсі Collection , він може застосовуватися до всіх списків та наборів .

4.2. Використання Java 8

Ми можемо використовувати Stream та Collectors таким чином, щоб об’єднати Списки :

List combined = Stream.concat(first.stream(), second.stream()).collect(Collectors.toList());

Це те саме, що ми зробили у випадку з масивами в розділі 3.2, але замість того, щоб перетворити його на масив, ми використали колектори, щоб перетворити його на список. Щоб детально дізнатись про колекціонерів , відвідайте Посібник із колекціонерів Java 8.

Ми також можемо використовувати flatMaps таким чином:

List combined = Stream.of(first, second).flatMap(Collection::stream).collect(Collectors.toList());

По-перше, ми використовуємо Stream.of (), який повертає послідовний потік двох списків - першого та другого . Потім ми передамо його в flatMap, який поверне вміст відображеного потоку після застосування функції відображення. Цей метод також обговорювався в статті «Об’єднання потоків у Java».

Щоб дізнатися більше про flatMap , перейдіть до цієї статті Baeldung.

4.3. Використання ListUtils від Apache Commons

CollectionUtils.union об’єднує дві колекції і повертає колекцію, яка містить усі елементи:

List combined = ListUtils.union(first, second);

Цей метод також обговорюється в Керівництві по колекціях колекцій Apache Commons CollectionUtils . Для отримання додаткової інформації перейдіть до розділу 4.9. цієї статті.

4.4. Використання гуави

Для об’єднання Списку за допомогою гуави ми будемо використовувати Iterable, який складається з методу concat () . Після об'єднання всіх колекцій ми можемо швидко отримати об'єднаний об'єкт List, як показано в цьому прикладі:

Iterable combinedIterables = Iterables .unmodifiableIterable(Iterables.concat(first, second)); List combined = Lists.newArrayList(combinedIterables);

5. Поєднання набору в Java

5.1. Звичайне рішення Java

As we had already discussed in section 4.1., Collection interface comes with a built-in addAll() method which can be used for copying Lists and Sets as well:

Set combined = new HashSet(); combined.addAll(first); combined.addAll(second);

5.2. Using Java 8 Streams

The same function that we used for List objects can be applied here:

Set combined = Stream .concat(first.stream(), second.stream()) .collect(Collectors.toSet());

The only notable difference here when comparing to list is that instead of using Collectors.toList(), we're using Collectors.toSet() to accumulate all the elements from the supplied two streams into a new Set.

And similar to Lists, when using flatMaps on Sets, it would look like:

Set combined = Stream.of(first, second) .flatMap(Collection::stream) .collect(Collectors.toSet());

5.3. Using Apache Commons

Similar to the ListUtils, we can also work with the SetUtils that does a union of Set elements:

Set combined = SetUtils.union(first, second);

5.4. Using from Guava

The Guava library provides us with straightforward Sets.union() method to combine Sets in Java:

Set combined = Sets.union(first, second);

6. Combining Map in Java

6.1. Plain Java Solution

We can make use of the Map interface which itself provides us with the putAll() method which copies all of the mappings from the supplied argument of Map object to the caller Map object:

Map combined = new HashMap(); combined.putAll(first); combined.putAll(second);

6.2. Using Java 8

Since Java 8, the Map class consists of merge() method which accepts a key, value, and a BiFunction. We can use this with a Java 8 forEach statement to achieve merging functionality:

second.forEach((key, value) -> first.merge(key, value, String::concat));

The third parameter, i.e., remapping function is useful when the same key-value pair is present in both source maps. This function specifies what should be done with those type of values.

We can also use flatMap like this:

Map combined = Stream.of(first, second) .map(Map::entrySet) .flatMap(Collection::stream) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, String::concat));

6.3. Using Apache Commons Exec

Apache Commons Exec provides us with a straightforward merge(Map first, Map second) method:

Map combined = MapUtils.merge(first, second);

6.4. Using Google Guava

Ми можемо використовувати ImmutableMap, надану бібліотекою Google Guava. Це putAll () метод пов'язує всі ключі даного МАП і значень в забудованій мапі:

Map combined = ImmutableMap.builder() .putAll(first) .putAll(second) .build();

7. Висновок

У цій статті ми пройшли різні підходи до об’єднання різних типів колекцій . Ми об’єднали масиви , Списки , Набори та Карти .

Як завжди, повні фрагменти коду з відповідними модульними тестами можна знайти на GitHub.