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.