HashMap and Hashtable both store key-value pairs, but they belong to different eras of Java. Most modern Java code should start with HashMap, then choose a concurrent collection when thread safety is required.
Quick comparison
| Feature | HashMap | Hashtable |
|---|---|---|
| Introduced | Java 1.2 Collections Framework | Java 1.0 legacy class |
| Thread safety | Not synchronized | Synchronized methods |
| Null keys and values | Allows one null key and multiple null values | Does not allow null keys or values |
| Typical use | General-purpose map | Legacy code compatibility |
Synchronization
Hashtable synchronizes most public methods. That sounds convenient, but it often creates coarse-grained locking. Every read and write competes for the same monitor, which can become expensive under concurrent access.
HashMap does not synchronize access. If multiple threads mutate the same map, external synchronization is required. In modern code, ConcurrentHashMap is usually a better choice because it is designed for concurrent reads and updates.
Null handling
HashMap allows one null key because keys must remain unique. It also allows multiple null values.
Hashtable rejects null keys and null values. This difference can matter when migrating legacy code because a value that was legal in a HashMap can throw a NullPointerException in a Hashtable.
Performance and API design
For single-threaded or request-scoped data, HashMap is generally faster and easier to reason about. It is also the collection most Java developers expect to see.
For shared mutable state, do not switch to Hashtable just because it is synchronized. Prefer ConcurrentHashMap, immutable maps, or a design that avoids shared mutation.
Recommendation
Use HashMap for normal map usage. Use ConcurrentHashMap for concurrent workloads. Treat Hashtable as a legacy type that you may need to read, maintain, or migrate away from.