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

Lov*_*ija 33 java hashtable hashmap

如JDK文档中所述,Hashtable不允许使用null键或值.HashMap允许一个空键和任意数量的空值.为什么是这样?

Jai*_*dra 42

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

HashMap更新,并且具有更高级的功能,这基本上只是对Hashtable功能的改进.创建HashMap时,它专门设计为将空值作为键处理并将其作为特殊情况处理.

编辑

来自Hashtable JavaDoc:

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

由于null不是对象,因此无法调用.equals().hashCode()使用它,因此Hashtable无法计算散列以将其用作键.

  • [`ConcurrentHashMap`](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html)是一个较新的类,但也有不允许null键或值的限制.他们出于性能原因添加了这个限制,因为支持null键和值需要做很多额外的工作,但在大多数情况下可能没用. (19认同)
  • 从答案中,我期待一个为什么Hashtable不允许空键或值的原因?尽管您建议使用新的和旧的。 (3认同)

小智 6

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

if (map.contains(key)) {
    return map.get(key);
} else {
    throw new KeyNotFoundException;
}
Run Code Online (Sandbox Code Playgroud)

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

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