正如 JDK 文档中指定的那样,Hashtable 不允许空键或空值。 HashMap 允许一个空键和任意数量的空值。为什么是这样?
原文由 Love Hasija 发布,翻译遵循 CC BY-SA 4.0 许可协议
正如 JDK 文档中指定的那样,Hashtable 不允许空键或空值。 HashMap 允许一个空键和任意数量的空值。为什么是这样?
原文由 Love Hasija 发布,翻译遵循 CC BY-SA 4.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 许可协议
4 回答1.2k 阅读✓ 已解决
4 回答1.2k 阅读✓ 已解决
1 回答2.5k 阅读✓ 已解决
2 回答715 阅读✓ 已解决
2 回答1.7k 阅读
2 回答1.7k 阅读
2 回答1.3k 阅读
Hashtable 是较旧的类,通常不鼓励使用它。也许他们看到需要一个空键,更重要的是 - 空值,并将其添加到 HashMap 实现中。
HashMap 较新,具有更高级的功能,基本上只是对 Hashtable 功能的改进。 HashMap 在创建时专门设计用于将空值作为键来处理,并将其作为一种特殊情况来处理。
编辑
来自
Hashtable
JavaDoc :Since
null
isn’t an object, you can’t call.equals()
or.hashCode()
on it, so theHashtable
can’t compute一个散列以将其用作密钥。