Java中HashMap和Hashtable之间的区别是什么?

对于非线程应用程序,哪个更有效?


当前回答

HashTable是同步的,如果您在单个线程中使用它,则可以使用HashMap,这是一个未同步的版本。未同步的对象通常性能更高。顺便说一句,如果多个线程同时访问HashMap,并且至少有一个线程在结构上修改了该映射,那么它必须在外部同步。您可以使用以下方法将未同步的映射打包到已同步的映射中:Map m=Collections.synchronizedMap(新HashMap(…));HashTable只能包含非空对象作为键或值。HashMap可以包含一个空键和空值。Map返回的迭代器是快速失败的,如果在创建迭代器之后的任何时候对映射进行了结构修改,则除了通过迭代器自己的remove方法之外,迭代器将抛出ConcurrentModificationException。因此,在并发修改的情况下,迭代器会快速而干净地失败,而不是在未来某个不确定的时间冒着任意、非确定性行为的风险。而Hashtable的键和元素方法返回的枚举不会快速失败。HashTable和HashMap是Java集合框架的成员(自从Java 2平台v1.2以来,HashTable被改进以实现Map接口)。HashTable被认为是遗留代码,如果需要线程安全的高度并发实现,文档建议使用ConcurrentHashMap代替HashTable。HashMap不保证返回元素的顺序。对于HashTable,我想它是相同的,但我不完全确定,我找不到明确说明这一点的ressource。

其他回答

除了这里已经提到的所有其他重要方面之外,CollectionsAPI(例如Map接口)一直在进行修改,以符合Java规范的“最新和最大”添加。

例如,比较Java 5 Map迭代:

for (Elem elem : map.keys()) {
  elem.doSth();
}

与旧的Hashtable方法相比:

for (Enumeration en = htable.keys(); en.hasMoreElements(); ) {
  Elem elem = (Elem) en.nextElement();
  elem.doSth();
}

在Java 1.8中,我们还承诺能够像使用好的旧脚本语言一样构造和访问HashMaps:

Map<String,Integer> map = { "orange" : 12, "apples" : 15 };
map["apples"];

更新:不,他们不会在1.8…:(

Project Coin的收藏增强功能是否将在JDK8中?

除了已经提到的差异之外,应该注意的是,自从Java8以来,HashMap动态地用TreeNodes(红黑树)替换每个bucket中使用的Nodes(链表),因此即使存在高哈希冲突,搜索时最坏的情况也是

HashMap的O(log(n))与Hashtable中的O(n)。

*上述改进尚未应用于Hashtable,而仅应用于HashMap、LinkedHashMap和ConcurrentHashMap。

仅供参考,目前,

TREEIFY_THRESHOLD=8:如果存储桶包含8个以上的节点,则链接列表将转换为平衡树。UNTREEIFY_THRESHOLD=6:当存储桶太小(由于删除或调整大小)时,树将转换回链接列表。

注意,很多答案都表明Hashtable是同步的。在实践中,这几乎不会给你带来什么好处。同步是在访问器/赋值器上进行的。方法将停止同时从映射中添加或删除两个线程,但在现实世界中,您通常需要额外的同步。

一个非常常见的习惯用法是“先检查后放”,即在Map中查找条目,如果它不存在,则添加它。无论使用Hashtable还是HashMap,这都不是原子操作。

可通过以下方式获得等效同步的HashMap:

Collections.synchronizedMap(myMap);

但要正确实现此逻辑,您需要以下形式的额外同步:

synchronized(myMap) {
    if (!myMap.containsKey("tomato"))
        myMap.put("tomato", "red");
}

即使迭代Hashtable的条目(或Collections.synchronizedMap获得的HashMap)也不是线程安全的,除非您还通过额外的同步来防止Map被修改。

ConcurrentMap接口(例如ConcurrentHashMap)的实现通过包括线程安全检查然后动作语义(如:

ConcurrentMap.putIfAbsent(key, value);

除了izb所说的,HashMap允许空值,而Hashtable不允许。

还要注意,Hashtable扩展了Dictionary类,作为Javadocs状态,该类已过时,已被Map接口取代。

HashMap和Hashtable都用于以键和值的形式存储数据。它们都使用哈希技术来存储唯一的键。但是HashMap和Hashtable类之间有很多不同,如下所示。