繁体   English   中英

Map.ofEntries 在使用 containsKey() 检查 NULL 键时给出空指针异常

[英]Map.ofEntries gives Null Pointer Exception on checking NULL key using containsKey()

我之前使用 HashMap 从常量映射中获取密钥。

containsKey()传递NULL 键时,我曾经得到FALSE

为了使代码看起来很花哨,我在上面尝试了 java-8。 所以,我开始使用 Map.ofEntries来构建我的地图,而不是 HashMap

令人惊讶的是,当 Null 键被传递给containsKey()方法时,我得到了Null Pointer Exception

String str = null;

Map<String,String> hashMap = new HashMap<>();
hashMap.put("k1", "v1");
System.out.print(hashMap.containsKey(str)); // This gives false

Map<String,String> ofEntriesMap = Map.ofEntries( Map.entry("k1", "v1")); 
System.out.print(ofEntriesMap.containsKey(str)); // Why this gives Null Pointer Exception ?

我无法弄清楚,为什么它在Map.ofEntries表现不同。

处理这种情况的最佳方法是什么?

Map的 javadoc 说:

不可修改的地图

Map.ofMap.ofEntriesMap.copyOf静态工厂方法提供了一种创建不可修改映射的便捷方法。 这些方法创建的 Map 实例具有以下特点:

  • 它们是不可修改的 不能添加、删除或更新键和值。 调用 Map 上的任何 mutator 方法将始终导致抛出UnsupportedOperationException 但是,如果包含的键或值本身是可变的,这可能会导致 Map 行为不一致或其内容似乎发生变化。
  • 它们不允许null键和值 尝试使用null键或值创建它们会导致NullPointerException
  • ...

相比之下, HashMap的 javadoc 说:

Map接口的基于哈希表的实现。 此实现提供了所有可选的映射操作,并允许null值和null HashMap类大致等同于Hashtable ,除了它是非同步的并且允许空值。)该类不保证映射的顺序; 特别是,它不保证订单会随着时间的推移保持不变。

...

而不是 HashMap,我开始使用 Map.ofEntries来构建我的地图

令人惊讶的是,当 Null 键被传递给 containsKey() 方法时,我得到了Null Pointer Exception

java.util.Map的文档部分说:

一些地图实现对它们可能包含的键和值有限制 例如,有些实现禁止空键和值,有些实现对其键的类型有限制。 尝试插入不合格的键或值会引发未经检查的异常,通常为NullPointerExceptionClassCastException 尝试查询不合格的键或值的存在可能会引发异常,或者可能只是返回 false; 一些实现会表现出前一种行为,而另一些会表现出后者。

(加了重点。)

正如Map.ofEntries()的回答已经观察到的那样,通过Map.ofEntries()创建的地图就是这样的实现。 具体来说,它们不允许空键和值。 尽管没有记录它们的containsKey()方法是否在提供 null 参数时执行抛出选项,但您需要在使用它们时考虑到这种可能性。

另一方面,正如 Andreas 还表明的, HashMap被记录为允许空键和值,因此当传递空参数时,它的containsKey()方法有望正常完成。

处理这种情况的最佳方法是什么?

您有两个主要选择:

  • 如果您想继续(直接)使用通过Map.ofEntries()创建的地图,那么您必须避免测试它是否包含空键。 由于您知道它不能包含空键,因此无需进行此类测试。

  • 如果您想依靠能够测试您的地图中是否存在空键,特别是如果您想要在其中包含空键或空值的选项,那么您一定不要使用Map.ofEntries()来创建它。 但是,您可以使用Map.ofEntries()进行初始化 例如:

     Map<String, String> myMap = Collections.unmodifiableMap( new HashMap<String, String>( Map.ofEntries( Map.Entry("k1", "v1") ) ) );

    另请注意,如果您在地图中放置的条目少于 11 个,则Map.of()Map.ofEntries()整洁。 而且,当然,如果您不关心地图是否可修改,那么您不必将其放入不可修改的包装器中。

这是由Map.ofEntries创建的不可修改映射的实现细节。

当您将null键添加到HashMap ,它会计算null哈希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 – 如果指定的键为空并且此映射不允许空键(可选)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM