65. Map Implementations Compared
HashMap is the general-purpose O(1) map; LinkedHashMap preserves insertion (or access) order; TreeMap is sorted; Hashtable is legacy โ avoid it; EnumMap and IdentityHashMap are specialised.
Explanation
HashMap<K,V>: O(1) average for get/put/remove. Allows one null key and multiple null values. Iteration order is unpredictable. Not thread-safe. Load factor default 0.75 โ resize when 75% full.
LinkedHashMap<K,V>: extends HashMap, maintains a doubly-linked list of entries for insertion-order iteration. Optional access-order mode (new LinkedHashMap<>(16, 0.75f, true)) โ entries are moved to the tail on get, enabling LRU caches.
TreeMap<K,V>: red-black tree, O(log n) operations, keys sorted by natural order or Comparator. Implements NavigableMap with floorEntry, ceilingEntry, subMap, headMap, tailMap. Does not allow null keys.
Hashtable: synchronised legacy class, does not allow null keys or values. Replaced by ConcurrentHashMap. Never use in new code.
Example
import java.util.*;
public class MapImplementations {
public static void main(String[] args) {
// HashMap: general purpose
Map<String, Integer> hash = new HashMap<>();
hash.put("one", 1); hash.put("two", 2); hash.put("three", 3);
hash.put(null, 0); // null key allowed!
System.out.println("HashMap: " + hash); // order unpredictable
// LinkedHashMap: insertion order
Map<String, Integer> linked = new LinkedHashMap<>();
linked.put("one", 1); linked.put("two", 2); linked.put("three", 3);
System.out.println("LinkedHashMap: " + linked); // {one=1, two=2, three=3}
// TreeMap: sorted order
TreeMap<String, Integer> tree = new TreeMap<>();
tree.put("banana", 2); tree.put("apple", 1); tree.put("cherry", 3);
System.out.println("TreeMap: " + tree); // {apple=1, banana=2, cherry=3}
System.out.println("firstEntry: " + tree.firstEntry()); // apple=1
System.out.println("headMap(<cherry): " + tree.headMap("cherry")); // {apple=1, banana=2}
// LRU cache using LinkedHashMap access-order mode
int capacity = 3;
Map<Integer, String> lru = new LinkedHashMap<>(16, 0.75f, true) {
@Override protected boolean removeEldestEntry(Map.Entry<Integer, String> e) {
return size() > capacity;
}
};
lru.put(1, "A"); lru.put(2, "B"); lru.put(3, "C");
lru.get(1); // access makes 1 most-recent
lru.put(4, "D"); // evicts least-recently-used (2)
System.out.println("LRU cache: " + lru); // {3=C, 1=A, 4=D}
}
}