4 Key differences between a HashMap and a Hashtable in Java

Overview

Hashtable and HashMap are common data structures to store key-value data in your Java application. While having similarities, there are some crucial differences you need to know as a Java developer. Let’s discuss the differences between these two data structures in this post.

Hashtable is thread-safe, HashMap is not

Consider the following code using HashMap:

    public static void main(String[] args) {
        //demonstrate the differences between HashMap and HashTable regarding synchronization
        var myMap = new HashMap<String, Integer>();
        myMap.put("key1", 1);

        //spawn 10 threads to modify the value of "key1"
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                myMap.put("key1", myMap.get("key1") + 1);
            }).start();
        }

        //wait for all threads to finish
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(myMap.get("key1"));

    }

What would this code print? The answer is no one knows for sure. Since HashMap is not thread-safe, some updates could be lost in the code above.

In fact, running the code multiple times would produce different result. This is one example:

HashMap is not thread-safe
HashMap is not thread-safe

On the other hand, using HashTable would solve the issue:

		var myTable = new Hashtable<String, Integer>();
        myTable.put("key1", 1);

        //spawn 100 threads to modify the value of "key1"
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                myTable.put("key1", myTable.get("key1") + 1);
            }).start();
        }

        //wait for all threads to finish
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Result using HashTable: " + myTable.get("key1"));

The result is consistent, for the above code, I always get 101 returned.

But why HashTable is thread-safe and HashMap is not? It’s because if you look into the implementation of HashTable, all methods are synchronized while that’s not the case with HashMap.

For example, this is the method put of HashTable:

public synchronized V put(K key, V value) {
//...
}

And this is the put method of HashMap

public V put(K key, V value) {
        //...
}

HashMap allows null key & value, HashTable doesn’t

The following code would throw NullPointerException (on line 2, if you comment line 2, the exception is still thrown by line 3)

var myTable = new Hashtable<String, Integer>();
myTable.put(null, 100);
mytable.put("Key2", null);

You cannot use null as key or value with HashTable
You cannot use null as a key or value with HashTable

However, if I use HashMap, there is not exception thrown at run time:

var myMap= new HashMap<String, Integer>();
myMap.put("key1", null);
myMap.put(null, 100);

Performance

In single-thread applications, HashMap tends to perform better due to the lack of synchronization. However, in multiple thread applications, you need to use synchronization on operations involving HashMap to maintain data integrity, which would put a cost on performance too.

Let’s consider the operation of creating a HashTable and a HashMap with 1_000_000 entries

    public static void main(String[] args) {
        var myMap= new HashMap<String, Integer>();
        var myTable = new Hashtable<String, Integer>();

        var beforeAddingToHashTable = System.currentTimeMillis();
        //add 1000000 entries to HashTable
        for (int i = 0; i < 1_000_000; i++) {
            myTable.put("key" + i, i);
        }
        var afterAddingToHashTable = System.currentTimeMillis();

        var beforeAddingToHashMap = System.currentTimeMillis();

        //add 1000000 entries to HashMap
        for (int i = 0; i < 1_000_000; i++) {
            myMap.put("key" + i, i);
        }

        var afterAddingToHashMap = System.currentTimeMillis();

        //compare the result
        System.out.println("Time to add 1000000 entries to HashTable: " + (afterAddingToHashTable - beforeAddingToHashTable));
        System.out.println("Time to add 1000000 entries to HashMap: " + (afterAddingToHashMap - beforeAddingToHashMap));
    }

Generally, the time taken to complete the operations on a HashMap is less than that of a HashTable. However, it depends on the condition of your machine and how large is the set.

Iterating over Entries

HashMap: HashMap allows you to iterate over its entries using an enhanced for loop or iterators. It provides methods like keySet(), values(), and entrySet() for this purpose.

Hashtable: Hashtable also offers methods for iteration, similar to HashMap. You can use keys(), values(), and entrySet().

        var myMap= new HashMap<String, Integer>();
        var myTable = new Hashtable<String, Integer>();

        myMap.put("Key1", 100);
        myMap.put("Key2", 200);

        myTable.put("Key1", 100);
        myTable.put("Key2", 200);

        //Iterate over the map
        for (var entry : myMap.entrySet()) {
            System.out.println(entry.getKey() + " " + entry.getValue());
        }

        myMap.values();
        //myMap.keys(); //this will not compile

        //Iterate over the table
        for (var entry : myTable.entrySet()) {
            System.out.println(entry.getKey() + " " + entry.getValue());
        }

        myTable.keys();
        myTable.values();

Conclusion

There you have it, the core differences between HashTable and HashMap in Java:

  • HashTable is thread-safe (by marking methods with synchronized) while HashMap is not
  • HashMap is generally faster on single-threaded applications due to the lack of synchronization
  • HashTable offers keys() to iterate over keys
  • HashMap allows null key and value while HashTable doesn’t

Leave a Comment