HashMap vs Hashtable in Java

When working with Java collections, you’ll often encounter two similar data structures: HashMap and Hashtable. Both are used to store key-value pairs, but they have significant differences in terms of performance, synchronization, and usage. Understanding these differences is crucial for choosing the right data structure for your application. In this article, we’ll explore the key differences between HashMap and Hashtable, provide examples, and discuss when to use each.


Overview of HashMap and Hashtable

HashMap

  • Introduced in Java 1.2 as part of the Java Collections Framework.
  • Allows one null key and multiple null values.
  • Not synchronized (not thread-safe by default).
  • Offers better performance for single-threaded applications.
  • Uses an iterator that is fail-fast, meaning it throws a ConcurrentModificationException if the map is modified while iterating.

Hashtable

  • Exists since Java 1.0 (legacy class).
  • Does not allow null keys or values.
  • Synchronized (thread-safe by default).
  • Slower performance compared to HashMap due to synchronization overhead.
  • Uses an enumerator that is not fail-fast.

Key Differences Between HashMap and Hashtable

FeatureHashMapHashtable
SynchronizationNot synchronized (thread-unsafe).Synchronized (thread-safe).
Null Keys/ValuesAllows one null key and multiple null values.Does not allow null keys or values.
PerformanceFaster for single-threaded applications.Slower due to synchronization overhead.
IterationFail-fast iterator.Enumerator is not fail-fast.
LegacyPart of the Java Collections Framework.Legacy class (since Java 1.0).
ExtensibilityCan be synchronized using Collections.synchronizedMap().No additional synchronization needed.

Examples of HashMap and Hashtable

HashMap Example

import java.util.HashMap;

public class HashMapExample {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("Alice", 25);
        map.put("Bob", 30);
        map.put(null, 40); // Allowed
        map.put("Charlie", null); // Allowed

        System.out.println(map); // Output: {null=40, Alice=25, Bob=30, Charlie=null}
    }
}

Hashtable Example

import java.util.Hashtable;

public class HashtableExample {
    public static void main(String[] args) {
        Hashtable<String, Integer> table = new Hashtable<>();
        table.put("Alice", 25);
        table.put("Bob", 30);
        // table.put(null, 40); // Throws NullPointerException
        // table.put("Charlie", null); // Throws NullPointerException

        System.out.println(table); // Output: {Alice=25, Bob=30}
    }
}

When to Use HashMap vs Hashtable

Use HashMap When:

  • You need better performance in a single-threaded environment.
  • You want to allow null keys or values.
  • You don’t require thread safety, or you can handle synchronization externally (e.g., using Collections.synchronizedMap()).

Use Hashtable When:

  • You need thread safety out of the box.
  • You are working in a legacy codebase that already uses Hashtable.
  • You don’t need to store null keys or values.

Synchronization in HashMap and Hashtable

Synchronizing HashMap

If you need a thread-safe version of HashMap, you can use Collections.synchronizedMap():

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

public class SynchronizedHashMapExample {
    public static void main(String[] args) {
        Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
        syncMap.put("Alice", 25);
        syncMap.put("Bob", 30);

        System.out.println(syncMap); // Output: {Alice=25, Bob=30}
    }
}

Hashtable Synchronization

Hashtable is already synchronized, so no additional steps are needed:

import java.util.Hashtable;

public class HashtableExample {
    public static void main(String[] args) {
        Hashtable<String, Integer> table = new Hashtable<>();
        table.put("Alice", 25);
        table.put("Bob", 30);

        System.out.println(table); // Output: {Alice=25, Bob=30}
    }
}

Performance Comparison

  • HashMap: Faster in single-threaded environments because it doesn’t have synchronization overhead.
  • Hashtable: Slower due to synchronization, but safer in multi-threaded environments.

Alternatives to Hashtable

For modern applications, consider using ConcurrentHashMap instead of Hashtable. It provides better performance and scalability in multi-threaded environments.

Example:

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        map.put("Alice", 25);
        map.put("Bob", 30);

        System.out.println(map); // Output: {Alice=25, Bob=30}
    }
}

Resources for Further Reading


Conclusion

While HashMap and Hashtable are similar in functionality, they differ significantly in terms of synchronization, performance, and support for null keys/values. Use HashMap for single-threaded applications or when you need better performance, and use Hashtable or ConcurrentHashMap for thread-safe scenarios. By understanding these differences, you can make informed decisions and write more efficient, robust Java code.

HashMap vs Hashtable HashMap in Java Hashtable in Java Java HashMap Java Hashtable HashMap vs Hashtable differences Java collections Java synchronization ConcurrentHashMap Java thread safety Java null keys Java performance Java data structures Java legacy classes Java Collections Framework