Map
的 javadoc 说:
不可修改的地图
Map.of
、Map.ofEntries
和 Map.copyOf
静态工厂方法提供了一种创建不可修改映射的便捷方法。这些方法创建的 Map 实例具有以下特点:
- 他们是unmodifiable。不能添加、删除或更新键和值。调用 Map 上的任何 mutator 方法总是会导致抛出
UnsupportedOperationException
。但是,如果包含的键或值本身是可变的,这可能会导致 Map 行为不一致或其内容似乎发生变化。
-
它们不允许
null
键和值。尝试使用 null
键或值创建它们会导致 NullPointerException
。
- ...
相反,HashMap
的 javadoc 说:
基于哈希表的 Map
接口实现。此实现提供了所有可选的映射操作,并允许 null
值和 null
键。 (HashMap
类大致等同于 Hashtable
,只是它是不同步的并且允许空值。)该类不保证映射的顺序;特别是,它不保证订单会随着时间的推移保持不变。
...
,
代替 HashMap,我开始使用 Map.ofEntries 来构建我的地图
令人惊讶的是,我在传递 Null 键时遇到了Null Pointer Exception
到 containsKey() 方法
java.util.Map
的文档部分说明:
某些地图实现对它们可能包含的键和值有限制。例如,某些实现禁止 null
键和值,有些对其类型有限制
键。尝试插入不合格的键或值会引发
未经检查的异常,通常是 NullPointerException
或
ClassCastException
。 试图查询一个
不合格的键或值可能会引发异常,或者可能只是
返回假;一些实现会表现出以前的行为
有些会展示后者。
(添加了强调。)
正如 @Andreas's answer 已经观察到的,通过 Map.ofEntries()
创建的地图就是这样的实现。具体来说,它们不允许空键和值。尽管没有记录它们的 containsKey()
方法是否在提供 null 参数时行使抛出选项,但您需要在使用它们时考虑到这种可能性。
另一方面,正如 Andreas 还表明的,HashMap
被记录为允许空键和值,因此当传递空参数时,它的 containsKey()
方法预计会正常完成。
处理这种情况的最佳方法是什么?
您有两个主要选择:
-
如果您想继续(直接)使用通过 Map.ofEntries()
创建的地图,那么您必须避免测试它是否包含空键。既然你知道它不能包含空键,这样的测试是不必要的。
-
如果您希望能够测试地图中是否存在空键,特别是如果您想要在其中包含空键或空值的选项,那么您不得使用 {{1}来创建它。但是,您可以使用 Map.ofEntries()
来初始化它。例如:
Map.ofEntries()
另请注意,如果您在地图中放置的条目少于 11 个,那么 Map<String,String> myMap = Collections.unmodifiableMap(
new HashMap<String,String>(
Map.ofEntries(
Map.Entry("k1","v1")
)
)
);
会比 Map.of()
更整洁一些。而且,当然,如果您不关心地图是否可修改,那么您不必将其放入不可修改的包装器中。
,
这是由 Map.ofEntries
创建的不可修改映射的实现细节。
当您将 null
键添加到 HashMap
时,它计算 null
的哈希值等于 0
。
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
但是 Map.ofEntries
会在只提供一对的情况下创建 ImmutableCollections.Map1
,否则会创建 ImmutableCollections.MapN
。
这是 ImmutableCollections.Map1::containsKey
的实现
public boolean containsKey(Object o) {
return o.equals(k0); // implicit nullcheck of o
}
您可以看到该评论指出 NullPointerException
是预期行为。至于 ImmutableCollections.MapN::containsKey
它使用显式空检查。
public boolean containsKey(Object o) {
Objects.requireNonNull(o);
return size > 0 && probe(o) >= 0;
}
如果您参考 Map::containsKey
Javadoc,您可以看到它明确表示此方法可能会或可能不会产生 NPE。
如果此映射包含指定键的映射,则返回 true。更多的
形式上,当且仅当此映射包含键 k 的映射使得 Objects.equals(key,k) 时,才返回 true。 (最多可以有一个这样的映射。)
参数:
key – 要测试其在此地图中是否存在的键
返回:
如果此映射包含指定键的映射,则为 true
抛出:
ClassCastException – 如果该键的类型不适合此地图(可选)
NullPointerException – 如果指定的键为空并且此映射不允许空键(可选)
本文链接:https://www.f2er.com/14110.html