1. 概述
Java 9 引入了 Map.of()
方法,使得创建不可变地图变得更加方便,以及 Map.ofEntries()
方法,它具有稍微不同的功能。
在这个教程中,我们将深入研究这两个不可变地图的静态工厂方法,并解释在何种情况下适合使用它们。
2. Map.of()
Map.of()
方法接受指定数量的键值对作为参数,返回一个包含每个键值对的不可变地图。参数中键值对的顺序与它们添加到地图中的顺序相同。如果尝试添加具有重复键的键值对,将抛出 IllegalArgumentException
。如果试图添加 null
的键或值,会抛出 NullPointerException
。
作为重载的静态工厂方法,第一个方法允许我们创建一个空地图:
static <K, V> Map<K, V> of() {
return (Map<K,V>) ImmutableCollections.EMPTY_MAP;
}
让我们看看它的用法:
Map<Long, String> map = Map.of();
Map<K, V>
接口中还定义了一个只接受一个键和值的方法:
static <K, V> Map<K, V> of(K k1, V v1) {
return new ImmutableCollections.Map1<>(k1, v1);
}
我们可以这样调用它:
Map<Long, String> map = Map.of(1L, "value1");
这些工厂方法共有 11 个重载版本,最多可以接受 10 个键和 10 个值,如我们在 OpenJDK 17 中所见:
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
}
尽管这些方法非常有用,但如果需要创建更多的方法,将会变得混乱。此外,我们不能使用 Map.of()
方法从现有键值对创建地图,因为这个方法只接受未定义的键值对作为参数。这时,Map.ofEntries()
方法就派上用场了。
3. Map.ofEntries()
Map.ofEntries()
方法接受任意数量的 Map.Entry<K, V>
对象作为参数,同样返回一个不可变地图。参数中键值对的顺序与它们添加到地图中的顺序相同。如果尝试添加具有重复键的键值对,也会抛出 IllegalArgumentException
。
根据 OpenJDK 17 的实现来看:
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
if (entries.length == 0) { // implicit null check of entries array
var map = (Map<K,V>) ImmutableCollections.EMPTY_MAP;
return map;
} else if (entries.length == 1) {
// implicit null check of the array slot
return new ImmutableCollections.Map1<>(entries[0].getKey(), entries[0].getValue());
} else {
Object[] kva = new Object[entries.length << 1];
int a = 0;
for (Entry<? extends K, ? extends V> entry : entries) {
// implicit null checks of each array slot
kva[a++] = entry.getKey();
kva[a++] = entry.getValue();
}
return new ImmutableCollections.MapN<>(kva);
}
}
使用可变参数(/java-varargs)实现,我们可以传递任意数量的条目。
例如,我们可以创建一个空地图:
Map<Long, String> map = Map.ofEntries();
或者创建并填充地图:
Map<Long, String> longUserMap = Map.ofEntries(Map.entry(1L, "User A"), Map.entry(2L, "User B"));
Map.ofEntries()
方法的一个主要优势是,我们还可以使用它从现有键值对创建地图。这在 Map.of()
方法中是无法做到的,因为它只接受未定义的键值对作为参数。
4. 总结
Map.of()
方法仅适用于最多包含 10 个元素的地图,因为它是通过 11 个不同的重载方法实现的,这些方法分别接受 0 到 10 个键值对。另一方面,Map.ofEntries()
方法可以用于任何大小的地图,因为它利用了可变参数(/java-varargs)特性。
完整的示例可在 GitHub 上找到。