提问



Java中HashMapHashtable之间有什么区别?[166] [167]


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

最佳参考


Java中HashMapHashtable之间存在一些差异:[168] [169]



  1. Hashtable是同步的,而HashMap则不是。这使得HashMap对于非线程应用程序更好,因为非同步对象通常比同步对象执行得更好。

  2. Hashtable不允许null键或值。 HashMap允许一个null键和任意数量的null值。

  3. HashMap的一个子类是LinkedHashMap,所以如果你想要可预测的迭代顺序(默认情况下是插入顺序),你可以轻松地换掉HashMap LinkedHashMap。如果您使用Hashtable,这并不容易。[171]



由于同步对您来说不是问题,我建议HashMap。如果同步成为一个问题,您也可以查看ConcurrentHashMap[172]

其它参考1


请注意,许多答案表明Hashtable已同步。 在实践中,这很少购买。同步在accessor/mutator上的方法将停止两个线程同时添加或从地图中删除,但在现实世界中,您经常需要额外的同步。


一个非常常见的习语是检查然后放 - 即在地图中查找条目,如果它尚不存在则添加它。无论您使用Hashtable还是HashMap,这都不是原子操作。


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


Collections.synchronizedMap(myMap);


但要正确实现此逻辑,您需要表单的其他同步:


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


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


ConcurrentMap接口的实现(例如ConcurrentHashMap)通过包含线程安全检查 - 然后 - 动作语义来解决其中的一些问题,例如:[173] [174]


ConcurrentMap.putIfAbsent(key, value);

其它参考2


Hashtable被视为遗留代码。 Hashtable无法使用HashMapHashMap的推导来完成,所以对于新的代码,我没有看到回到Hashtable的任何理由。]]。

其它参考3


在访谈中经常会询问这个问题,以检查候选人是否理解收集类的正确用法,并了解可用的替代解决方案。



  1. HashMap类大致相当于Hashtable,除了它是非同步的并且允许空值。 (HashMap允许空值作为键和值,而Hashtable不允许空值)。

  2. HashMap不保证地图的顺序会随着时间的推移保持不变。

  3. HashMap是非同步的,而Hashtable是同步的。

  4. HashMap中的Iterator是故障安全的,而Hashtable的枚举器不是,如果任何其他Thread通过添加或删除除Iterator自己的remove()方法之外的任何元素来修改地图,则抛出ConcurrentModificationException。但这不是保证行为,JVM将尽最大努力完成。



关于一些重要条款的说明



  1. 同步意味着只有一个线程可以在一个时间点修改哈希表。基本上,这意味着在对哈希表执行更新之前的任何线程都必须获取对象的锁定,而其他线程将等待锁定被释放。

  2. 故障安全与迭代器的上下文相关。如果已在集合对象上创建了迭代器,并且某些其他线程尝试在结构上修改集合对象,则将引发并发修改异常。其他线程可能会调用set方法,因为它不会在结构上修改集合。但是,如果在调用set之前,集合已经在结构上进行了修改,则会抛出IllegalArgumentException。/li>
  3. 结构修改意味着删除或插入可有效改变地图结构的元素。



HashMap可以同步


Map m = Collections.synchronizeMap(hashMap);


Map提供了Collection视图,而不是直接支持迭代
 通过枚举对象。集合视图大大增强了
 界面的表现力,如本节后面所述。
 Map允许您迭代键,值或键值对;
 Hashtable不提供第三种选择。 Map提供了一种安全的方式
 删除迭代中的条目; Hashtable没有。
 最后,Map修复了Hashtable界面中的一个小缺陷。
 Hashtable有一个名为contains的方法,如果是,则返回true
 Hashtable包含给定值。鉴于它的名字,你会期待这一点
 如果Hashtable包含给定键,则返回true的方法,因为
 关键是Hashtable的主要访问机制。地图
 接口通过重命名方法消除了这种混淆的来源
 中的containsValue。此外,这提高了界面的一致性 -
 containsValue parallels containsKey。



  地图界面[175]


其它参考4


HashMap:使用哈希码索引数组的Map接口的实现。
Hashtable:嗨,1998年召集。他们想要回收他们的集合API。


但是说真的,你最好远离Hashtable。对于单线程应用程序,你不需要额外的同步开销。对于高度并发的应用程序,偏执同步可能会导致饥饿,死锁或不必要的垃圾收集暂停。就像Tim Howland指出的那样,你可以用ConcurrentHashMap代替。

其它参考5


请记住,HashTable是Java集合框架(JCF​​)引入之前的遗留类,后来被改进以实现Map接口。 VectorStack也是如此。


因此,在新代码中总是远离它们,因为JCF总是有更好的替代方法,正如其他人所指出的那样。


这是您将发现有用的Java集合备忘单。请注意,灰色块包含遗留类HashTable,Vector和Stack。[176]




其它参考6


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


还要注意,Hashtable扩展了Dictionary类,它作为Javadocs状态已经过时并且已被Map接口替换。[177]

其它参考7


看看这张图表。它提供了不同数据结构与HashMap和Hashtable之间的比较。比较准确,清晰,易于理解。


Java Collection Matrix [178]

其它参考8


Hashtable类似于HashMap并且具有类似的界面。建议您使用HashMap,除非您需要支持遗留应用程序或需要同步,因为Hashtables方法是同步的。因此,在您的情况下,因为您不是多线程,HashMaps是您最好的选择。

其它参考9


hashtable和hashmap之间的另一个关键区别是HashMap中的Iterator是快速失​​败而Hashtable的枚举器不是,如果任何其他Thread通过添加或删除除Iterator自己的remove()之外的任何元素来修改地图,则抛出ConcurrentModificationException但这不是一种保证行为,将由JVM尽最大努力完成。


我的来源:http://javarevisited.blogspot.com/2010/10/difference-between-hashmap-and.html [179]

其它参考10


已发布许多好的答案。我添加了一些新点并总结了它。


HashMapHashtable都用于以密钥和值格式存储数据。两者都使用散列技术来存储唯一键。
但是下面给出了HashMap和Hashtable类之间的许多区别。


HashMap中


1)HashMap不同步。它不是线程安全的,并且在没有适当的同步代码的情况下不能在许多线程之间共享
2)HashMap允许一个空键和多个空值
3)HashMap是JDK 1.2中引入的新类。

4)HashMap很快。

5)我们可以通过调用此代码来使HashMap同步
         Map m = Collections.synchronizedMap(HashMap);,点击
6)HashMap由迭代器遍历。

7)HashMap中的迭代器是快速失败的。

8)HashMap继承AbstractMap类。


哈希表


1)Hashtable是同步的。它是线程安全的,可以与许多线程共享
2)Hashtable不允许任何空键或值
3)Hashtable是遗留类。

4)Hashtable很慢。

5)Hashtable在内部同步,不能不同步
6)Hashtable由Enumerator和Iterator遍历。

7)Hashtable中的枚举器不是快速失败的。

8)Hashtable继承Dictionary类。


进一步阅读Java中的HashMap和Hashtable有什么区别?[180]


[181]

其它参考11


除了这里已经提到的所有其他重要方面,Collections API(例如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中进行?

其它参考12



  • HashTable是同步的,如果您在单个线程中使用它,则可以使用HashMap,这是一个不同步的版本。非同步对象通常更具性能。顺便说一下,如果多个线程同时访问HashMap,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步。
    你可以使用以下方法将未同步的地图包装在同步的地图中:[183]​​]] [184]


    Map m = Collections.synchronizedMap(new HashMap(...));
    

  • HashTable只能包含非空对象作为键或值。 HashMap可以包含一个空键和空值。

  • Map返回的迭代器是快速失败的,如果在创建迭代器之后的任何时候对映射进行结构修改,除非通过迭代器自己的remove方法,迭代器将抛出ConcurrentModificationException因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险。然后 Hashtable返回的枚举键和元素方法不是快速失败的。

  • HashTable和HashMap是Java Collections Framework的成员(自Java 2平台v1.2起,HashTable被改进以实现Map接口)。[185]

  • HashTable被认为是遗留代码,如果需要线程安全的高度并发实现,文档建议使用ConcurrentHashMap代替Hashtable。[186]

  • HashMap并不保证返回元素的顺序。对于HashTable,我猜它是一样的,但我不完全确定,我找不到明确说明这一点的资源。


其它参考13


HashMapHashtable也有很大的算法差异。之前没有人提到这一点,所以这就是我提出它的原因。HashMap将构建一个具有两个大小幂的哈希表,动态增加它,这样你最多可以有八个元素(冲突)对于一般的元素类型,它会很好地激发元素。但是,如果你知道你在做什么,Hashtable实现提供了更好更精细的哈希控制,即你可以使用例如最接近的素数来修复表大小数字到您的值域大小,这将导致比HashMap更好的性能,即在某些情况下更少的冲突。


除了在这个问题中广泛讨论的显而易见的差异之外,我认为Hashtable是一个手动驱动汽车,你可以更好地控制散列和HashMap作为通常表现良好的自动驱动对应物。

其它参考14


Hashtable是同步的,而HashMap不是。这使得Hashtable比Hashmap慢。


对于非线程应用程序,请使用HashMap,因为它们在功能方面是相同的。

其它参考15


基于这里的信息,我建议使用HashMap。我认为最大的优点是Java会阻止你在迭代它时修改它,除非你通过迭代器完成它。[187]

其它参考16


对于线程应用程序,您可以经常使用ConcurrentHashMap - 取决于您的性能要求。

其它参考17


A Collection - 有时称为容器 - 只是一个将多个元素组合成一个单元的对象。 Collection用于存储,检索,操作和传递聚合数据。集合框架 W 是用于表示和操作集合的统一架构。 [188] [189]


使用HashMap JDK1.2 和Hashtable JDK1.0 表示在<Key, Value>对中表示的一组对象。每个<Key, Value>对称为Entry对象。条目集合由HashMapHashtable的对象引用。集合中的键必须是唯一的或独特的。 [[因为它们用于检索特定键的映射值。集合中的值可以重复。]] [190] [191]





« 超类,旧版和集合框架成员


Hashtable是JDK1.0中引入的遗留类,它是Dictionary类的子类。从JDK1.2重新设计Hashtable以实现Map接口以构成集合框架的成员。 HashMap是JDK1.2中引入的Java Collection Framework的成员。 HashMap是AbstractMap类的子类。 [192]




public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable { ... }

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { ... }




« 初始容量和负载系数


容量是哈希表中的桶数,初始容量就是创建哈希表时的容量。请注意,哈希表是打开的:在hash collision的情况下,单个存储桶存储多个条目,必须按顺序搜索。负载因子是衡量哈希表在其容量自动增加之前可以获得多长的度量。 [193]


HashMap使用默认初始容量(16)和默认加载因子(0.75)构造一个空哈希表。 Hashtable使用默认初始容量(11)和加载因子/填充率(0.75)构造空哈希表的位置。


[194]


« 哈希冲突情况下的结构修改


HashMapHashtable在哈希冲突的情况下,它们将地图条目存储在链表中。 从Java8 for HashMap 如果哈希桶超过某个阈值,该桶将从linked list of entries to a balanced tree切换。它改善了从O(n)到O(log n)的最坏情况性能。在将列表转换为二叉树时,哈希码用作分支变量。如果同一个存储桶中有两个不同的哈希码,则一个被认为更大,并且位于树的右侧,另一个位于左侧。但是当两个哈希码相等时,HashMap假设密钥是可比较的,并且比较密钥以确定方向,以便可以维持某个顺序。使HashMap的键可比较是一种好习惯。在桶大小达到TREEIFY_THRESHOLD = 8时添加条目将条目的链接列表转换为平衡树时,在删除小于TREEIFY_THRESHOLD且最多UNTREEIFY_THRESHOLD = 6的条目时,会将平衡树重新转换为条目的链接列表。 Java 8 SRC,stackpost [195] [197]


« 集合视图迭代,失败快速和失败安全


    +--------------------+-----------+-------------+
    |                    | Iterator  | Enumeration |
    +--------------------+-----------+-------------+
    | Hashtable          | fail-fast |    safe     |
    +--------------------+-----------+-------------+
    | HashMap            | fail-fast | fail-fast   |
    +--------------------+-----------+-------------+
    | ConcurrentHashMap  |   safe    |   safe      |
    +--------------------+-----------+-------------+


Iterator本质上是一种快速失败。即如果在迭代时修改集合而不是它自己的remove()方法,则抛出ConcurrentModificationException。 Enumeration在本质上是故障安全的。如果在迭代时修改了集合,则不会抛出任何异常。 [199] [200]


根据Java API Docs,Iterator始终优于Enumeration。


注意: Enteration接口的功能由Iterator接口复制。此外,Iterator添加了一个可选的删除操作,并且具有更短的方法名称。新实现应考虑使用Iterator而不是Enumeration。


在Java 5中引入了ConcurrentMap接口:ConcurrentHashMap - 由哈希表支持的高度并发,高性能ConcurrentMap实现。执行检索时,此实现永远不会阻塞,并允许客户端选择更新的并发级别。它旨在作为Hashtable的直接替代:除了实现ConcurrentMap之外,它还支持Hashtable特有的所有遗留方法。[201]



  • 每个HashMapEntry s值都是易失性的,从而确保竞争修改和后续读取的细粒度一致性;每次阅读都反映了最近完成的更新

  • 迭代器和枚举是失败安全的 - 自迭代器/枚举创建以来某些时候反映状态;这允许以降低一致性为代价同时进行读取和修改。它们不会抛出ConcurrentModificationException。但是,迭代器设计为一次只能由一个线程使用。

  • Hashtable类似,但与HashMap不同,此类不允许将null用作键或值。





public static void main(String[] args) {

    //HashMap<String, Integer> hash = new HashMap<String, Integer>();
    Hashtable<String, Integer> hash = new Hashtable<String, Integer>();
    //ConcurrentHashMap<String, Integer> hash = new ConcurrentHashMap<>();

    new Thread() {
        @Override public void run() {
            try {
                for (int i = 10; i < 20; i++) {
                    sleepThread(1);
                    System.out.println("T1 :- Key"+i);
                    hash.put("Key"+i, i);
                }
                System.out.println( System.identityHashCode( hash ) );
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
    }.start();
    new Thread() {
        @Override public void run() {
            try {
                sleepThread(5);
                // ConcurrentHashMap  traverse using Iterator, Enumeration is Fail-Safe.

                // Hashtable traverse using Enumeration is Fail-Safe, Iterator is Fail-Fast.
                for (Enumeration<String> e = hash.keys(); e.hasMoreElements(); ) {
                    sleepThread(1);
                    System.out.println("T2 : "+ e.nextElement());
                }

                // HashMap traverse using Iterator, Enumeration is Fail-Fast.
                /*
                for (Iterator< Entry<String, Integer> > it = hash.entrySet().iterator(); it.hasNext(); ) {
                    sleepThread(1);
                    System.out.println("T2 : "+ it.next());
                    // ConcurrentModificationException at java.util.Hashtable$Enumerator.next
                }
                */

                /*
                Set< Entry<String, Integer> > entrySet = hash.entrySet();
                Iterator< Entry<String, Integer> > it = entrySet.iterator();
                Enumeration<Entry<String, Integer>> entryEnumeration = Collections.enumeration( entrySet );
                while( entryEnumeration.hasMoreElements() ) {
                    sleepThread(1);
                    Entry<String, Integer> nextElement = entryEnumeration.nextElement();
                    System.out.println("T2 : "+ nextElement.getKey() +" : "+ nextElement.getValue() );
                    //java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode
                    //                                          at java.util.HashMap$EntryIterator.next
                    //                                          at java.util.Collections$3.nextElement
                }
                */
            } catch ( Exception e ) {
                e.printStackTrace();
            }
        }
    }.start();

    Map<String, String> unmodifiableMap = Collections.unmodifiableMap( map );
    try {
        unmodifiableMap.put("key4", "unmodifiableMap");
    } catch (java.lang.UnsupportedOperationException e) {
        System.err.println("UnsupportedOperationException : "+ e.getMessage() );
    }
}
static void sleepThread( int sec ) {
    try {
        Thread.sleep( 1000 * sec );
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}




« 空键和空值


HashMap允许最多一个空键和任意数量的空值。其中Hashtable甚至不允许单个null键和null值,如果键或值为null,则抛出NullPointerException。 实施例


« 同步,线程安全


Hashtable在内部同步。因此,在多线程应用程序中使用Hashtable非常安全。其中HashMap未在内部同步。因此,在没有外部同步的多线程应用程序中使用HashMap是不安全的。您可以使用Collections.synchronizedMap()方法在外部同步HashMap


« 效果


由于Hashtable在内部同步,这使得HashtableHashMap稍慢。





@看到



  • 红黑树是一种自平衡二元搜索树

  • Java 8中HashMap的性能改进


其它参考18


除了已经提到的差异之外,应该注意的是,自Java 8起,HashMap动态地用TreeNodes(红黑树)替换每个桶中使用的节点(链表),这样即使存在高哈希冲突也是如此,最糟糕的情况搜索时是[204] [205]


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


*上述改进尚未适用于Hashtable,但仅适用于HashMapLinkedHashMapConcurrentHashMap


仅供参考,目前,



  • TREEIFY_THRESHOLD = 8:如果一个桶包含8个以上的节点,则链表将转换为平衡树。

  • UNTREEIFY_THRESHOLD = 6:当桶变得太小(由于删除或调整大小)时,树会转换回链表。


其它参考19


1。HashmapHashTable都存储密钥和值。


2。Hashmap可以将一个密钥存储为nullHashtable无法存储null


3. HashMap未同步但Hashtable已同步。


4 HashMap可与Collection.SyncronizedMap(map)同步


Map hashmap = new HashMap();

Map map = Collections.SyncronizedMap(hashmap);

其它参考20


HashTable和HashMaps有5个基本区别。



  1. Maps允许您迭代和检索键,值以及两个键值对,其中HashTable具备所有这些能力。

  2. 在Hashtable中有一个函数contains(),使用起来非常混乱。因为contains的含义略有偏差。是否包含密钥或包含值?难以理解。在Maps中我们有ContainsKey()和ContainsValue()函数,它们很容易理解。

  3. 在hashmap中,您可以安全地在迭代时删除元素。在哈希表中不可能的地方。

  4. HashTables默认是同步的,因此可以轻松地与多个线程一起使用。默认情况下,HashMaps不同步,因此只能与单个线程一起使用。但您仍然可以使用Collections util类的synchronizedMap(Map m)函数将HashMap转换为同步。

  5. HashTable不会允许空键或空值.HashMap允许一个空键和多个空值。


其它参考21


我的小贡献:



  

      
  1. HashtableHashMap之间的第一个也是最重要的不同之处在于,HashMap不是线程安全的,而Hashtable是一个线程安全的集合。

  2.   
  3. HashtableHashMap之间的第二个重要区别是性能,因为HashMap不同步,它的性能优于Hashtable

  4.   
  5. HashtableHashMap的第三个区别是Hashtable是过时的类,你应该用ConcurrentHashMap代替Java中的Hashtable

  6.   


其它参考22


HashTable是jdk中的遗留类,不应该再使用了。用ConcurrentHashMap替换它的用法。如果你不需要线程安全,请使用HashMap,它不是线程安全但更快并且使用更少的内存。[206]]] [207] [208] [209]

其它参考23


1)Hashtable是同步的,而hashmap不是。
2)另一个区别是HashMap中的迭代器是故障安全的,而Hashtable的枚举器不是。如果你在迭代时更改地图,你就会知道。


3)HashMap允许空值,而Hashtable不允许。

其它参考24


HashMap: - 它是java.util包中可用的类,它用于以键和值格式存储元素。


Hashtable: - 它是一个遗留类,在集合框架中被识别

其它参考25


Hashtable:


Hashtable 是一种保留键值对值的数据结构。它不允许键和值都为null。如果添加空值,您将获得NullPointerException。它是同步的。所以它带来了它的成本。只有一个线程可以在特定时间访问 HashTable


示例:


import java.util.Map;
import java.util.Hashtable;

public class TestClass {

    public static void main(String args[ ]) {
    Map<Integer,String> states= new Hashtable<Integer,String>();
    states.put(1, "INDIA");
    states.put(2, "USA");

    states.put(3, null);    //will throw NullPointerEcxeption at runtime

    System.out.println(states.get(1));
    System.out.println(states.get(2));
//  System.out.println(states.get(3));

    }
}


HashMap中:


HashMap 就像 Hashtable ,但它也接受键值对。它允许键和值都为null。它的性能优于HashTable,因为它是unsynchronized


示例:


import java.util.HashMap;
import java.util.Map;

public class TestClass {

    public static void main(String args[ ]) {
    Map<Integer,String> states = new HashMap<Integer,String>();
    states.put(1, "INDIA");
    states.put(2, "USA");

    states.put(3, null);    // Okay
    states.put(null,"UK");

    System.out.println(states.get(1));
    System.out.println(states.get(2));
    System.out.println(states.get(3));

    }
}

其它参考26


HashMap和HashTable



  • 关于HashMap和HashTable的一些重要观点。
       请阅读以下详细信息。



1)Hashtable和Hashmap实现java.util.Map接口
2)Hashmap和Hashtable都是基于哈希的集合。并致力于散列。
所以这些是HashMap和HashTable的相似之处。



  • HashMap和HashTable有什么区别?



1)第一个区别是HashMap不是线程安全的,而HashTable是ThreadSafe

2)HashMap在性能方面更好,因为它不是线程安全的。虽然Hashtable性能明智并不好,因为它是线程安全的。所以多线程不能同时访问Hashtable。

其它参考27


HashMaps为您提供了同步自由,调试更加轻松

其它参考28


HashMap被模拟,因此可用于GWT client code,而Hashtable则不然。

其它参考29


同步或线程安全:


哈希映射不是同步的,因此它不是安全的,并且如果没有适当的同步块,它不能在多个线程之间共享,而Hashtable是同步的,因此它是线程安全的。


空键和空值:


HashMap允许一个空键和任意数量的空值.Hashtable不允许使用null键或值。


迭代值:


HashMap中的Iterator是一个快速失败的迭代器,而Hashtable的枚举器不是,如果任何其他Thread通过添加或删除除Iterator自己的remove()方法之外的任何元素而在结构上修改地图,则抛出ConcurrentModificationException。


超级和遗产:


HashMap是AbstractMap类的子类,而Hashtable是Dictionary类的子类。


效果:


由于HashMap未同步,因此与Hashtable相比更快。


请参阅http://modernpathshala.com/Article/1020/difference-between-hashmap-and-hashtable-in-java以获取示例和面试与Java集合相关的问题和测验[210]