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

Объединение различных типов коллекций в Java

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

1. Введение

В этом кратком руководстве мы рассмотрим различные способы объединения коллекций в Java.

Мы рассмотрим различные подходы с использованием Java и внешних сред, таких как Guava, Apache и т. д. Чтобы ознакомиться с коллекциями, ознакомьтесь с этой серией статей здесь .

2. Внешние библиотеки для работы с коллекциями

Наряду с нативными подходами мы также будем использовать внешние библиотеки. Добавьте следующие зависимости в pom.xml :

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>

Последние версии можно найти на 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);

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

Это собственное решение Java, поэтому для него не требуются внешние библиотеки.

3.2. Использование потокового API Java 8

Потоки предлагают эффективный способ перебора нескольких различных типов коллекций. Чтобы начать работу с потоками, перейдите к учебнику Java 8 Stream API Tutorial .

Чтобы объединить массивы с помощью 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 Commons предоставляет нам метод 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. Использование собственного метода addAll () коллекции ``

Сам интерфейс Collection предоставляет нам метод addAll() , который добавляет все элементы указанной коллекции в вызывающий объект. Это также подробно обсуждается в этой статье ForEach:

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

Поскольку этот метод предоставляется в самом родительском интерфейсе инфраструктуры коллекций, т . е. в интерфейсе коллекции , его можно применять ко всем спискам и наборам .

4.2. Использование Java 8

Мы можем использовать Stream и Collectors следующим образом для объединения списков :

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

Это то же самое, что мы сделали в случае с массивами в разделе 3.2, но вместо преобразования в массив мы использовали сборщики для преобразования его в список. Чтобы узнать больше о коллекторах , посетите Руководство по коллекторам Java 8 .

Мы также можем использовать flatMaps следующим образом:

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

Во- первых, мы используем Stream.of() , который возвращает последовательный поток из двух списков — первого и второго . Затем мы передадим его в flatMap , который вернет содержимое сопоставленного потока после применения функции сопоставления. Этот метод также обсуждался в статье «Объединение потоков в Java ».

Чтобы узнать больше о flatMap , перейдите к этой статье ForEach .

4.3. Использование ListUtils из Apache Commons

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

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

Этот метод также обсуждается в Руководстве по коллекциям Apache Commons CollectionUtils . Для получения дополнительной информации перейдите к разделу 4.9. этой статьи.

4.4. Использование гуавы

Чтобы объединить список с помощью Guava, мы будем использовать Iterable , который состоит из метода concat() . После объединения всех коллекций мы можем быстро получить объединенный объект List , как показано в этом примере:

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

5. Объединение набора в Java

5.1. Простое Java-решение

Как мы уже обсуждали в разделе 4.1., интерфейс Collection имеет встроенный метод addAll() , который также можно использовать для копирования списков и наборов :

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

5.2. Использование потоков Java 8

Здесь можно применить ту же функцию, которую мы использовали для объектов List :

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

Единственная заметная разница здесь при сравнении со списком заключается в том, что вместо использования Collectors.toList() мы используем Collectors.toSet() для накопления всех элементов из предоставленных двух потоков в новый набор .

Аналогично Lists , при использовании flatMaps в Sets это будет выглядеть так:

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

5.3. Использование Apache Commons

Подобно ListUtils , мы также можем работать с SetUtils , который выполняет объединение элементов Set :

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

5.4. Использование из Гуавы

Библиотека Guava предоставляет нам простой метод Sets.union() для объединения наборов в Java:

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

6. Объединение карты в Java

6.1. Простое Java-решение

Мы можем использовать интерфейс Map , который сам предоставляет нам метод putAll() , который копирует все сопоставления из предоставленного аргумента объекта Map в вызывающий объект Map :

Map<Object, Object> combined = new HashMap<>();
combined.putAll(first);
combined.putAll(second);

6.2. Использование Java 8

Начиная с Java 8, класс Map состоит из метода merge() , который принимает ключ, значение и функцию BiFunction . Мы можем использовать это с оператором forEach в Java 8 для достижения функциональности слияния:

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

Третий параметр, то есть функция переназначения, полезен, когда одна и та же пара ключ-значение присутствует в обеих исходных картах. Эта функция указывает, что следует делать с этими типами значений.

Мы также можем использовать flatMap следующим образом:

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

6.3. Использование Apache Commons Exec

Apache Commons Exec предоставляет нам простой метод слияния (сначала Map<K,V>, затем Map<K,V>) :

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

6.4. Использование Google Гуавы

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

Map<String, String> combined = ImmutableMap.<String, String>builder()
.putAll(first)
.putAll(second)
.build();

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

В этой статье мы рассмотрели различные подходы к объединению различных типов коллекций . Мы объединили массивы , списки , наборы и карты .

Как всегда, полные фрагменты кода с соответствующими модульными тестами можно найти на GitHub.