为什么 Hashtable 不允许空键或空值?

新手上路,请多包涵

正如 JDK 文档中指定的那样,Hashtable 不允许空键或空值。 HashMap 允许一个空键和任意数量的空值。为什么是这样?

原文由 Love Hasija 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 916
2 个回答

Hashtable 是较旧的类,通常不鼓励使用它。也许他们看到需要一个空键,更重要的是 - 空值,并将其添加到 HashMap 实现中。

HashMap 较新,具有更高级的功能,基本上只是对 Hashtable 功能的改进。 HashMap 在创建时专门设计用于将空值作为键来处理,并将其作为一种特殊情况来处理。

编辑

来自 Hashtable JavaDoc

要成功地从 Hashtable 中存储和检索对象,用作键的对象必须实现 hashCode 方法和 equals 方法。

Since null isn’t an object, you can’t call .equals() or .hashCode() on it, so the Hashtable can’t compute一个散列以将其用作密钥。

原文由 Jainendra 发布,翻译遵循 CC BY-SA 3.0 许可协议

Hashtable 和 ConcurrentHashMap 不允许空键或值的主要原因是因为期望它们将在多线程环境中使用。一分钟,让我们假设允许空值。在这种情况下,哈希表的“get”方法具有不明确的行为。如果在映射中找不到该键,它可以返回 null;如果找到该键且其值为 null,则它可以返回 null。当代码需要空值时,它通常会检查键是否存在于映射中,以便它可以知道键是否存在或键存在但值为空。现在这段代码在多线程环境中中断。让我们看看下面的代码:

 if (map.contains(key)) {
    return map.get(key);
} else {
    throw new KeyNotFoundException;
}

在上面的代码中,假设线程 t1 调用 contains 方法并找到键,它假定键存在并准备好返回值,无论它是否为 null。现在,在它调用 map.get 之前,另一个线程 t2 从地图中删除了该键。现在 t1 恢复并返回 null。但是根据代码,t1 的正确答案是 KeyNotFoundException,因为密钥已被删除。但它仍然返回 null,因此预期的行为被打破了。

现在,对于一个常规的 HashMap,假定它将被单个线程调用,因此不可能在“包含”检查和“获取”的过程中删除键。所以 HashMap 可以容忍空值。但是对于 Hashtable 和 ConcurrentHashMap,期望很明确,即多个线程将对数据进行操作。因此,他们不能允许空值并给出错误的答案。同样的逻辑也适用于钥匙。现在计数器参数可以是 - 对于 Hashtables 和 ConcurrentHashMaps 的非空值,contains 和 get 步骤可能会失败,因为另一个线程可以在执行第二步之前修改映射/表。这是正确的,它可能发生。但是由于 Hashtables 和 ConcurrentHashMaps 不允许空键和空值,所以它们没有必要首先实现包含和获取检查。他们可以直接获取值,因为他们知道如果 get 方法返回 null,唯一的原因是键不存在,而不是因为值可能为 null。只有 HashMap 才需要 contains 和 get 检查,因为它们允许空值,因此需要解决关于是否找不到键或值为空的歧义。

原文由 punitoza 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题