繁体   English   中英

为什么 java.util.Map.containsKey 会为不支持空键的映射抛出空指针异常?

[英]Why does java.util.Map.containsKey throw a null pointer exception for maps which don't support null keys?

Java 文档是这样说的:

抛出:

ClassCastException - 如果该键的类型不适合此映射(可选)

NullPointerException - 如果指定的键为空并且此映射不允许空键(可选)

我相信这个决定有一个很好的理由,但我不知道它到底是什么。 即使映射不允许空值作为键,containsKey 也不应该总是返回 false 吗? 如果地图不允许键,则 Null 显然不是地图中的键,所以我认为它应该返回 false。

我想到的特定实例是 TreeMap。 出于性能原因,我将 Map 实例从 HashMap 更改为 TreeMap,这导致了一个微妙的错误,因为 HashMap 的 containsKey 不会引发空指针异常。 我觉得这种类型的更改没有充分的理由导致像这样的微妙错误。


编辑我知道 NullPointerException 的(可选)性质。 在我看来,它的可选性质并不能解释为什么允许它

为了说明为什么我对此感到困惑,containsKey 本质上是通过相等来比较键。 在某种程度上,我来自函数式背景,其中(比如 Haskell)containsKey 的等价物将对其具有相等约束,并且对所有可以通过相等进行比较的值都有效。

Object.equalsjava 文档

对于任何非空引用值 x,x.equals(null) 应返回 false。

因此,我认为如果映射不支持空键,则 containsKey 必须返回 false,因为实现“应该”等效于使用 k.equals(input) 迭代键。

我相信这是一个设计决定。

有两种可能的情况:

1.您在支持空键的地图上使用 containsKey。 作为此函数的用户,您希望得到 true 或 false。 绝对没有理由返回 nullPointerException,因为我们将 'null' 视为任何其他键,所以就像您期望 'someKey' 不存在时返回 false 一样,对于 null 也是如此。

2.您在不支持空键的地图上使用 containsKey。 返回 false 将是一个奇怪的决定,因为它不是一个可能的键。 此外,用户可能有对他试图用作键的某个对象的引用。 用户更愿意得到一个 NullPointerException 异常,所以他会意识到这种情况,试图获取/设置一个空对象作为键。

您的论点平均适用于ClassCastException :即使映射不允许该类型的值作为键,也不应该containsKey总是返回 false 吗?

回答:API(记录的行为)不是强制实现检查给定键的有效性,而是允许针对无效键值抛出异常。

请注意,这两个例外都被列为“(可选)”,这意味着是否执行该操作取决于实现。 实现可以选择简单地返回false ,或者它可以选择抛出这些异常之一。

实现可能会选择为此添加特殊逻辑,因此如果算法“本机”抛出异常,那就这样吧。 API 被记录为允许这种默认行为。

例如, TreeMap将本机抛出ClassCastException ,因为在尝试调用compare() / compareTo()时会发生这种情况。 HashMap不关心对象类型,因此永远不会抛出ClassCastException

对于不支持空键的映射, containsKey()的逻辑可能会或可能不会做一些事情,如果给定的键是空的,则抛出NullPointerException ,这是一个有效的结果,因此该逻辑不必浪费额外的代码来处理它。

首先,在Map<K, V>接口中声明了containsKey(Object key) ,它没有声明抛出任何东西,因此它取决于实现

如果问题是为什么实现不在内部执行所有这些 (null, cast) 检查以及为什么它们会抛出异常,我认为这是因为设计,并且有充分的理由,明确给出输出出了什么问题。

注意:

  1. 您的密钥可以是已定义密钥类型的子类型,因此,可能需要对其进行强制转换。 由于它是内部转换的,因此运行时不知道您将提供什么作为参数。 因此,最好抛出这个;
  2. 您的密钥可能是明确的,也可能是在幕后的某个地方(例如,在多线程场景中), get null ,这也是处理此场景的原因。

请注意,这两个异常都被定义为可选异常,因此,再次强调,实现应该抛出它们并不是必须的。

暂无
暂无

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

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