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

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

1. Вступление

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

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

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);

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

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

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

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

Чтобы объединить массивы с использованиемStream, мы можем использовать этот код:

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

Stream.concat() создает объединенный поток, в котором за элементами первого потока следуют элементы второго потока, который после этого преобразуется в массив с использованием методаtoArray() .

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

Мы вернемся к этому методу в разделах 4.2. и 5.2. чтобы увидеть, как мы можем использовать тот же метод дляLists иSets.

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

Библиотека Apache Commons предоставляет нам методaddAll() из пакетаArrayUtils. Мы можем предоставить массив назначения и источника в качестве параметров, и этот метод возвратит объединенный массив:

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

Этот метод также подробно обсуждается в статьеArray Processing with Apache Commons Lang 3.

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

Guava предоставляет нам методconcat() для той же цели:

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

Он может использоваться с различными типами данных и принимает два исходных массива вместе с литералом класса для возврата объединенного массива.

4. ОбъединениеList в Java

4.1. ИспользованиеCollection собственного методаaddAll()

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

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


Поскольку этот метод предоставляется в большинстве родительских интерфейсов платформы Collections, то есть в интерфейсеCollection, его можно применять ко всемLists иSets.

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

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

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


Это то же самое, что мы сделали в случаеArrays в разделе 3.2, но вместо преобразования его в массив мы использовали сборщики для преобразования его в список. Чтобы подробнее узнать оCollectors, посетитеGuide to Java 8’s Collectors.

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

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


First, we’re using Stream.of() which returns a sequential stream of two lists –  first and second. We’ll then pass it to flatMap which will return the contents of a mapped stream after applying the mapping function. Этот метод также обсуждался в статьеMerging Streams in Java.

Чтобы узнать больше оflatMap, перейдите кthis example article.

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

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

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


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

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

To merge a List using Guava, we’ll use Iterable which consists of the concat() method. После объединения всех коллекций мы можем быстро получить объединенный объектList, как показано в этом примере:

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





5. ОбъединениеSet в Java

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

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

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



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

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

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


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

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

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



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

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

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



5.4. Использование от Guava

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

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





6. ОбъединениеMap в Java

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

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

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

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

Since Java 8, the Map class consists of merge() method which accepts a key, value, and a BiFunction. Мы можем использовать это с оператором Java 8forEach для достижения функциональности слияния:

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

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

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

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. Использование Apache Commons Exec

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

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

6.4. Использование Google Guava

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

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

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

В этой статье мы рассмотрели разные подходы к объединению разных типовCollections. Мы объединилиarrays,Lists,Sets иMaps.

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