Java Maps: HashMap vs. LinkedHashMap vs. TreeMap Explained
CK 3788 Created at
22700
In Java, the Map interface is part of the java.util package and represents a collection that stores key-value pairs. Each key in a Map must be unique, and it maps to a single value. Maps are crucial for various programming scenarios where you need to associate data points, like a dictionary or a lookup table. The Java platform provides several concrete implementations of the Map interface, each offering different characteristics in terms of ordering, performance, and memory usage. The most commonly used implementations are HashMap, LinkedHashMap, and TreeMap.
HashMap
HashMap is a hash table-based implementation of the Map interface. It provides fast (constant-time average) performance for the basic operations (get and put).
Characteristics:
Unordered: Does not guarantee any specific order of elements; the order can change over time.
Nulls: Allows one null key and multiple null values.
Performance: Offers average constant-time O(1) performance for put, get, and remove operations, assuming a good hash function and minimal collisions. In the worst-case scenario (many hash collisions leading to a degenerate linked list), performance can degrade to O(n).
Synchronization: HashMap is not synchronized. If multiple threads access a hash map concurrently and at least one of the threads modifies the map, it must be synchronized externally.
Memory: Generally efficient in memory unless dealing with a very high load factor and poor hash functions.
Underlying Data Structure: Hash table (an array of buckets). Each bucket typically stores a linked list of entries, but in Java 8 and later, if a bucket contains too many entries (a "treeify" threshold, typically 8), the linked list is converted into a balanced red-black tree to improve worst-case performance from O(n) to O(log n).
Use Cases:
General-purpose mapping where the order of elements is not important.
Implementing caches where fast lookups are crucial.
Counting frequencies of items.
LinkedHashMap
LinkedHashMap extends HashMap but also maintains a doubly-linked list running through all its entries. This linked list defines the iteration order, which is normally the order in which keys were inserted into the map (insertion order).
Characteristics:
Ordered (Insertion Order): Iterates over its elements in the order in which the entries were inserted. An alternate constructor allows creating a LinkedHashMap that orders its entries by access order (least-recently accessed to most-recently accessed), useful for implementing LRU caches.
Nulls: Allows one null key and multiple null values, similar to HashMap.
Performance: Performance is marginally slower than HashMap due to the overhead of maintaining the linked list, but put, get, and remove operations are still O(1) on average. Iteration performance is generally better than HashMap as it traverses the linked list.
Synchronization: LinkedHashMap is not synchronized.
Memory: Uses slightly more memory than HashMap to maintain the linked list.
Underlying Data Structure: Hash table (like HashMap) + doubly-linked list. Each entry in the map is also a node in the doubly-linked list.
Use Cases:
When you need a map that remembers the order in which elements were added.
Implementing LRU (Least Recently Used) caches (using the access order constructor).
Building web applications where session attributes need to preserve order.
LinkedHashMap maintains insertion order (by default). This means there's a clear "oldest" (first inserted) and "latest" (last inserted) element.
1. Deleting the Oldest Object with LinkedHashMap
The oldest object is simply the first entry in the LinkedHashMap's iteration order. You can obtain its key using an iterator and then remove it.
Method: 1. Check if the map is empty. 2. Get an iterator for the entrySet().
3. Get the next() entry from the iterator, which will be the oldest. 4. Use map.remove(key) to delete it.
Note on removeEldestEntry: LinkedHashMap also has a protected method removeEldestEntry(Map.Entry eldest) which you can override to implement a policy for automatic removal of the oldest entry when a new entry is added. This is commonly used for implementing LRU (Least Recently Used) caches, but it's not for explicit, on-demand deletion of the oldest element.
2. Deleting the Latest Object with LinkedHashMap
The latest object is the last entry in the LinkedHashMap's iteration order. Since LinkedHashMap iterators are forward-only, getting the last element requires iterating through all elements or converting to a collection that allows direct access to the last element.
Method: 1. Check if the map is empty. 2. Iterate through the entrySet() and keep track of the last element encountered. Alternatively, and often simpler: Convert entrySet() into a List, then get the last element from the list. 3. Use map.remove(key) to delete it.
Example (using List conversion for simplicity):
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class LinkedHashMapDeletion {
public static void main(String[] args) {
LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
lhm.put("Apple", 1);
lhm.put("Banana", 2);
lhm.put("Cherry", 3);
lhm.put("Date", 4); // Latest
System.out.println("Original LinkedHashMap: " + lhm);
// --- Deleting the latest object ---
String latestKey = null;
Integer latestValue = null;
if (!lhm.isEmpty()) {
// Convert the entry set to a list to easily access the last element
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(lhm.entrySet());
Map.Entry<String, Integer> latestEntry = entryList.get(entryList.size() - 1);
latestKey = latestEntry.getKey();
latestValue = lhm.remove(latestKey); // Remove by key
System.out.println("\nDeleted latest object:");
System.out.println("Key: " + latestKey + ", Value: " + latestValue);
} else {
System.out.println("\nMap is empty, no latest object to delete.");
}
System.out.println("LinkedHashMap after deleting latest: " + lhm);
// Expected output: {Apple=1, Banana=2, Cherry=3}
}
}
Alternative for latest (Java 8 Stream):
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
public class LinkedHashMapDeletionStream {
public static void main(String[] args) {
LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
lhm.put("Apple", 1);
lhm.put("Banana", 2);
lhm.put("Cherry", 3);
lhm.put("Date", 4);
System.out.println("Original LinkedHashMap: " + lhm);
if (!lhm.isEmpty()) {
Optional<Map.Entry<String, Integer>> latestEntryOptional = lhm.entrySet().stream()
.reduce((first, second) -> second); // The accumulator returns the second element, effectively keeping the last one seen.
if (latestEntryOptional.isPresent()) {
Map.Entry<String, Integer> latestEntry = latestEntryOptional.get();
String latestKey = latestEntry.getKey();
Integer latestValue = lhm.remove(latestKey);
System.out.println("\nDeleted latest object (Stream):");
System.out.println("Key: " + latestKey + ", Value: " + latestValue);
}
} else {
System.out.println("\nMap is empty, no latest object to delete.");
}
System.out.println("LinkedHashMap after deleting latest (Stream): " + lhm);
}
}
TreeMap
TreeMap is a NavigableMap implementation based on a Red-Black tree. It stores entries in ascending order of keys, either according to their natural ordering (if keys implement Comparable) or according to a custom Comparator provided at map creation time.
Characteristics:
Ordered (Sorted Order): Stores and retrieves elements in a sorted order based on the keys. Keys must be comparable.
Nulls: Does not allow null keys (throws NullPointerException if you try to insert one) because it relies on key comparison. It allows multiple null values.
Performance: Operations like put, get, and remove have O(log n) time complexity due to the tree traversal required to locate or insert elements.
Synchronization: TreeMap is not synchronized.
Memory: Generally uses more memory than HashMap or LinkedHashMap due to the overhead of storing nodes with left/right pointers and color information for the tree structure.
Underlying Data Structure: Red-Black tree (a self-balancing binary search tree).
Use Cases:
When you need keys to be sorted (e.g., retrieving elements in a specific range).
Implementing dictionaries or symbol tables where sorted order is important.
When you need to perform range queries (e.g., finding all keys between X and Y).
Common Map Operators (Methods)
The following are common methods provided by the Map interface, which are implemented by HashMap, LinkedHashMap, and TreeMap:
Method Signature
Description
V put(K key, V value)
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
V get(Object key)
Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
V remove(Object key)
Removes the mapping for a key from this map if it is present. Returns the value to which this map previously associated the key, or null if the map contained no mapping for the key.
boolean containsKey(Object key)
Returns true if this map contains a mapping for the specified key.
boolean containsValue(Object value)
Returns true if this map maps one or more keys to the specified value.
int size()
Returns the number of key-value mappings in this map.
boolean isEmpty()
Returns true if this map contains no key-value mappings.
void clear()
Removes all of the mappings from this map.
Set keySet()
Returns a Set view of the keys contained in this map.
Collection values()
Returns a Collection view of the values contained in this map.
Set> entrySet()
Returns a Set view of the mappings contained in this map. Each element in the set is a Map.Entry object.
V getOrDefault(Object key, V defaultValue)
Returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key. (Java 8+)
void putAll(Map m)
Copies all of the mappings from the specified map to this map.
V replace(K key, V value)
Replaces the entry for the specified key only if it is currently mapped to some value. (Java 8+)
Comparison of HashMap vs LinkedHashMap vs TreeMap
Feature
HashMap
LinkedHashMap
TreeMap
Order of Elements
No guaranteed order; unordered.
Insertion order (or access order).
Natural order of keys (or custom Comparator).
Null Keys
Allowed (one).
Allowed (one).
Not allowed (throws NullPointerException).
Null Values
Allowed (multiple).
Allowed (multiple).
Allowed (multiple).
Underlying Data Structure
Hash table (array of buckets, potentially with linked lists or red-black trees).
Hash table + Doubly-linked list.
Red-Black Tree.
Performance (Average)
O(1) for put, get, remove.
O(1) for put, get, remove.
O(log n) for put, get, remove.
Iteration Performance
O(n) but order is arbitrary.
O(n) and preserves order.
O(n) and preserves sorted order.
Synchronization
Not synchronized.
Not synchronized.
Not synchronized.
Memory Usage
Moderate.
Slightly higher (for linked list pointers).
Higher (for tree node pointers and color).
Use Cases
General-purpose map, fast lookups where order doesn't matter.
Caches, maintaining insertion order, LRU caches.
Sorted maps, range queries, naturally ordered data.