Contents
1. Introduction
Java provides several ways of storing key-value maps (also known as dictionaries). The most common ones are java.util.HashMap and java.util.Hashtable. Let us explore the difference between these two classes.
2. Synchronization
Synchronization is a mechanism in Java for preventing multiple threads from interfering with each other and eliminating memory consistency errors.
When one variable (a resource) is visible to multiple threads at the same time, consistency issues arise when one thread attempts to modify the value while another thread is accessing it. To prevent these issues, some form of synchronization must be used.
While synchronization helps in eliminating consistency errors, it adds an overhead when used. In a single-threaded program (or when you can guarantee that a single thread will access the resource), you can use HashMap to eliminate this overhead. Create a HashMap as follows:
HashMap<String,Object> map = new HashMap<>(); map.put("currentTime", new Date());
However, when accessing or modifying a dictionary shared between multiple threads, you must use Hashtable. The following shows how to create a Hashtable:
Hashtable<String,Integer> tbl = new Hashtable(); tbl.put("count", 32);
3. Using Null
Keys or Values
When your dictionary needs to contain null
keys or values, you cannot use Hashtable since this is not allowed. You must use HashMap in this case.
If you need multiple threads reading or writing the HashMap, you can wrap the HashMap using Collections.synchronizedMap() as follows:
HashMap<String,Object> map = Collections.synchronizedMap(new HashMap<>()); map.put(...);
A HashMap can contain one null
key and any number of nulls for values.
4. Predictable Iteration Order
A subclass of HashMap is LinkedHashMap which maintains a doubly-linked list of the entries in the Map. This allows traversal of the Map entries in a predictable order (in the order that the entries were inserted into the Map). If you need such a predictable ordering of the entries, then you can easily replace the HashMap with a LinkedHashMap as follows:
HashMap<String,Object> map = new LinkedHashMap<>(); map.put(...);
When using a Hashtable, such a predictable iteration order is not possible. If this is required, use a LinkedHashMap with a Collections.synchronizedMap() wrapper as above.
5. Iterating using Enumerator
While both HashMap and Hashtable support iteration over the entries using the entrySet(), Hashtable also provides an Enumeration of the entries using the Hashtable.elements() method. In addition, a Hashtable.keys() method also returns an Enumeration over the keys of the Hashtable.
Hashtable<String,Object> tbl = ...; for(Enumeration<String> keys = tbl.keys() ; tbl.hasMoreElements() ; ) { System.out.println(keys.nextElement()); }
Conclusion
Here is how you can decide when to use HashMap or Hashtable:
- For using as a shared resource between multiple threads in a single program, a Hashtable is preferred.
- When the dictionary needs to contain null keys or values, a HashMap must be used.
- A HashMap can be used in a multi-threaded environment by wrapping it with Collections.synchronizedMap().