What are the differences between a HashMap and a Hashtable in Java?

后端 未结 30 2382
青春惊慌失措
青春惊慌失措 2020-11-21 13:30

What are the differences between a HashMap and a Hashtable in Java?

Which is more efficient for non-threaded applications?

30条回答
  •  醉话见心
    2020-11-21 13:58

    A Collection — sometimes called a container — is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data. A collections framework W is a unified architecture for representing and manipulating collections.

    The HashMap JDK1.2 and Hashtable JDK1.0, both are used to represent a group of objects that are represented in pair. Each pair is called Entry object. The collection of Entries is referred by the object of HashMap and Hashtable. Keys in a collection must be unique or distinctive. [as they are used to retrieve a mapped value a particular key. values in a collection can be duplicated.]


    « Superclass, Legacy and Collection Framework member

    Hashtable is a legacy class introduced in JDK1.0, which is a subclass of Dictionary class. From JDK1.2 Hashtable is re-engineered to implement the Map interface to make a member of collection framework. HashMap is a member of Java Collection Framework right from the beginning of its introduction in JDK1.2. HashMap is the subclass of the AbstractMap class.

    public class Hashtable extends Dictionary implements Map, Cloneable, Serializable { ... }
    
    public class HashMap extends AbstractMap implements Map, Cloneable, Serializable { ... }
    

    « Initial capacity and Load factor

    The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created. Note that the hash table is open: in the case of a "hash collision", a single bucket stores multiple entries, which must be searched sequentially. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased.

    HashMap constructs an empty hash table with the default initial capacity (16) and the default load factor (0.75). Where as Hashtable constructs empty hashtable with a default initial capacity (11) and load factor/fill ratio (0.75).

    « Structural modification in case of hash collision

    HashMap, Hashtable in case of hash collisions they store the map entries in linked lists. From Java8 for HashMap if hash bucket grows beyond a certain threshold, that bucket will switch from linked list of entries to a balanced tree. which improve worst-case performance from O(n) to O(log n). While converting the list to binary tree, hashcode is used as a branching variable. If there are two different hashcodes in the same bucket, one is considered bigger and goes to the right of the tree and other one to the left. But when both the hashcodes are equal, HashMap assumes that the keys are comparable, and compares the key to determine the direction so that some order can be maintained. It is a good practice to make the keys of HashMap comparable. On adding entries if bucket size reaches TREEIFY_THRESHOLD = 8 convert linked list of entries to a balanced tree, on removing entries less than TREEIFY_THRESHOLD and at most UNTREEIFY_THRESHOLD = 6 will reconvert balanced tree to linked list of entries. Java 8 SRC, stackpost

    « Collection-view iteration, Fail-Fast and Fail-Safe

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

    Iterator is a fail-fast in nature. i.e it throws ConcurrentModificationException if a collection is modified while iterating other than it’s own remove() method. Where as Enumeration is fail-safe in nature. It doesn’t throw any exceptions if a collection is modified while iterating.

    According to Java API Docs, Iterator is always preferred over the Enumeration.

    NOTE: The functionality of Enumeration interface is duplicated by the Iterator interface. In addition, Iterator adds an optional remove operation, and has shorter method names. New implementations should consider using Iterator in preference to Enumeration.

    In Java 5 introduced ConcurrentMap Interface: ConcurrentHashMap - a highly concurrent, high-performance ConcurrentMap implementation backed by a hash table. This implementation never blocks when performing retrievals and allows the client to select the concurrency level for updates. It is intended as a drop-in replacement for Hashtable: in addition to implementing ConcurrentMap, it supports all of the "legacy" methods peculiar to Hashtable.

    • Each HashMapEntrys value is volatile thereby ensuring fine grain consistency for contended modifications and subsequent reads; each read reflects the most recently completed update

    • Iterators and Enumerations are Fail Safe - reflecting the state at some point since the creation of iterator/enumeration; this allows for simultaneous reads and modifications at the cost of reduced consistency. They do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.

    • Like Hashtable but unlike HashMap, this class does not allow null to be used as a key or value.

    public static void main(String[] args) {
    
        //HashMap hash = new HashMap();
        Hashtable hash = new Hashtable();
        //ConcurrentHashMap 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 e = hash.keys(); e.hasMoreElements(); ) {
                        sleepThread(1);
                        System.out.println("T2 : "+ e.nextElement());
                    }
                    
                    // HashMap traverse using Iterator, Enumeration is Fail-Fast.
                    /*
                    for (Iterator< Entry > it = hash.entrySet().iterator(); it.hasNext(); ) {
                        sleepThread(1);
                        System.out.println("T2 : "+ it.next());
                        // ConcurrentModificationException at java.util.Hashtable$Enumerator.next
                    }
                    */
                    
                    /*
                    Set< Entry > entrySet = hash.entrySet();
                    Iterator< Entry > it = entrySet.iterator();
                    Enumeration> entryEnumeration = Collections.enumeration( entrySet );
                    while( entryEnumeration.hasMoreElements() ) {
                        sleepThread(1);
                        Entry 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 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();
        }
    }
    

    « Null Keys And Null Values

    HashMap allows maximum one null key and any number of null values. Where as Hashtable doesn’t allow even a single null key and null value, if the key or value null is then it throws NullPointerException. Example

    « Synchronized, Thread Safe

    Hashtable is internally synchronized. Therefore, it is very much safe to use Hashtable in multi threaded applications. Where as HashMap is not internally synchronized. Therefore, it is not safe to use HashMap in multi threaded applications without external synchronization. You can externally synchronize HashMap using Collections.synchronizedMap() method.

    « Performance

    As Hashtable is internally synchronized, this makes Hashtable slightly slower than the HashMap.


    @See

    • A red–black tree is a kind of self-balancing binary search tree
    • Performance Improvement for HashMap in Java 8

提交回复
热议问题