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
nullkey and multiplenullvalues. - 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
ConcurrentModificationExceptionif the map is modified while iterating.
Hashtable
- Exists since Java 1.0 (legacy class).
- Does not allow
nullkeys or values. - Synchronized (thread-safe by default).
- Slower performance compared to
HashMapdue to synchronization overhead. - Uses an enumerator that is not fail-fast.
Key Differences Between HashMap and Hashtable
| Feature | HashMap | Hashtable |
|---|---|---|
| Synchronization | Not synchronized (thread-unsafe). | Synchronized (thread-safe). |
| Null Keys/Values | Allows one null key and multiple null values. | Does not allow null keys or values. |
| Performance | Faster for single-threaded applications. | Slower due to synchronization overhead. |
| Iteration | Fail-fast iterator. | Enumerator is not fail-fast. |
| Legacy | Part of the Java Collections Framework. | Legacy class (since Java 1.0). |
| Extensibility | Can 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
nullkeys 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
nullkeys 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
- Oracle Java Documentation:
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.