在Java中组合不同类型的集合

2023/06/07

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上找到CommonsCommons-execGuava的最新版本。

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 使用Java 8 Stream API

Stream提供了一种有效的方法来迭代几种不同类型的集合。要开始使用流,请转到Java 8 Stream API教程

要使用Stream组合数组,我们可以使用以下代码:

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

Stream.concat()创建一个串联流,其中第一个流的元素后面是第二个流的元素,然后使用toArray()方法将其转换为数组

创建流的过程在不同类型的集合中是相同的。但是,我们可以用不同的方式收集它,以从中检索不同的数据结构。

3.3 使用来自Apache Commons的ArrayUtils

Apache Commons为我们提供了ArrayUtils包中的addAll()方法。我们可以提供目标数组和源数组作为参数,此方法将返回一个组合数组:

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

使用Apache Commons Lang3处理数组一文中也详细讨论了此方法。

3.4 使用Guava

出于同样的目的,Guava为我们提供了concat()方法:

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

它可以与不同的数据类型一起使用,并且它接收两个源数组以及Class以返回组合数组。

4. Java中的组合列表

4.1 使用Collection原生addAll()方法

Collection接口本身为我们提供了addAll()方法,它将指定集合中的所有元素添加到调用者对象中。这篇文章也对此进行了详细讨论:

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

由于该方法是在Collection框架的最父接口Collection接口中提供的,因此可以跨所有List和Set应用。

4.2 使用Java 8

我们可以通过以下方式使用Stream和Collectors来组合Lists:

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

这与我们在3.2节中对数组所做的相同,但我们没有将其转换为数组,而是使用收集器将其转换为列表。要详细了解收集器,请访问Java 8收集器指南

我们也可以这样使用flatMap:

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

首先,我们使用Stream.of()返回两个列表的顺序流-first和second。然后我们将它传递给flatMap,它将在应用映射函数后返回映射流的内容。此方法也在Java中合并流一文中进行了讨论。

要了解有关flatMap的更多信息,请转至这篇文章

4.3 使用来自Apache Commons的ListUtils

CollectionUtils.union合并两个集合并返回一个包含所有元素的集合:

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

4.4 使用Guava

要使用Guava合并List,我们将使用由concat()方法组成的Iterable。拼接所有集合后,我们可以快速得到组合的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()方法,该方法也可用于Lists和Sets:

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

5.2 使用Java 8 Stream

可以在此处应用我们用于List对象的相同函数:

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

与list相比,这里唯一显著的区别是我们没有使用Collectors.toList(),而是使用Collectors.toSet()将提供的两个流中的所有元素累积到一个新的Set中

与Lists类似,在Sets上使用flatMap时,它看起来像:

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

Guava库为我们提供了直接的Sets.union()方法来组合Java中的集合:

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

6. Java中组合Map

6.1 普通Java解决方案

我们可以利用Map接口,它本身为我们提供了putAll()方法,该方法将所有Map从提供的Map对象参数复制到调用方Map对象:

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

6.2 使用Java 8

从Java 8开始,Map类由接收键、值和BiFunction的merge()方法组成。我们可以将其与Java 8 forEach语句一起使用来实现合并功能:

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

第三个参数,即重映射函数在两个源Map中存在相同的键值对时很有用。此函数指定应如何处理这些类型的值。

我们也可以像这样使用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为我们提供了一个简单的merge(Mapfirst, Mapsecond)方法:

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

6.4 使用Guava

我们可以使用Google的Guava库提供的ImmutableMap。它的putAll()方法将所有给定Map的键和值关联到构建的Map中:

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

7. 总结

在本文中,我们通过不同的方法来组合不同类型的集合。我们合并了数组、List、Set和Map。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章