Java LinkedHashMap

HashMap with predictable insertion-order iteration

🔗 What is LinkedHashMap?

LinkedHashMap combines HashMap's fast performance with predictable iteration order. It maintains insertion order using a doubly-linked list, perfect for ordered key-value storage needs.


// LinkedHashMap maintains insertion order
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("Third", 3);
map.put("First", 1);
map.put("Second", 2);
System.out.println(map); // {Third=3, First=1, Second=2}
                                    

LinkedHashMap Key Features

📋

Insertion Order

Maintains the order elements were added

LinkedHashMap<String, String> colors = new LinkedHashMap<>();
colors.put("R", "Red");
colors.put("G", "Green");
colors.put("B", "Blue");
// Always iterates: R, G, B
âš¡

Fast Performance

Same O(1) performance as HashMap

LinkedHashMap<String, Integer> cache = new LinkedHashMap<>();
cache.put("key1", 100);  // O(1)
Integer val = cache.get("key1"); // O(1)
cache.remove("key1");    // O(1)
🔄

Access Order

Optional access-order iteration mode

// Access-order LinkedHashMap (LRU cache)
LinkedHashMap<String, Integer> lru = 
    new LinkedHashMap<>(16, 0.75f, true);
lru.put("A", 1);
lru.put("B", 2);
lru.get("A"); // A moves to end
💾

LRU Cache

Perfect for implementing LRU caches

class LRUCache<K,V> extends LinkedHashMap<K,V> {
    private int maxSize;
    
    LRUCache(int maxSize) {
        super(16, 0.75f, true);
        this.maxSize = maxSize;
    }
    
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return size() > maxSize;
    }
}

🔹 Creating and Using LinkedHashMap

Basic LinkedHashMap operations with order preservation:

import java.util.*;

public class LinkedHashMapExample {
    public static void main(String[] args) {
        // Create LinkedHashMap
        LinkedHashMap<String, String> userProfiles = new LinkedHashMap<>();
        
        // Add users in specific order
        userProfiles.put("user001", "Alice Johnson");
        userProfiles.put("user003", "Charlie Brown");
        userProfiles.put("user002", "Bob Smith");
        userProfiles.put("user004", "Diana Prince");
        
        // Iteration maintains insertion order
        System.out.println("User profiles (insertion order):");
        for (Map.Entry<String, String> entry : userProfiles.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        
        // Update existing user (order unchanged)
        userProfiles.put("user002", "Robert Smith");
        
        // Add new user (goes to end)
        userProfiles.put("user005", "Eve Wilson");
        
        System.out.println("\nAfter updates:");
        userProfiles.forEach((id, name) -> 
            System.out.println(id + ": " + name));
        
        // Compare with HashMap (random order)
        HashMap<String, String> hashMap = new HashMap<>(userProfiles);
        System.out.println("\nSame data in HashMap (random order):");
        hashMap.forEach((id, name) -> 
            System.out.println(id + ": " + name));
    }
}

Output:

User profiles (insertion order):

user001: Alice Johnson

user003: Charlie Brown

user002: Bob Smith

user004: Diana Prince


After updates:

user001: Alice Johnson

user003: Charlie Brown

user002: Robert Smith

user004: Diana Prince

user005: Eve Wilson

🔹 Access-Order LinkedHashMap

Using access-order mode for LRU-style behavior:

// Create access-order LinkedHashMap
LinkedHashMap<String, String> accessOrderMap = new LinkedHashMap<>(16, 0.75f, true);

// Add some data
accessOrderMap.put("page1", "Home Page");
accessOrderMap.put("page2", "About Page");
accessOrderMap.put("page3", "Contact Page");
accessOrderMap.put("page4", "Products Page");

System.out.println("Initial order:");
accessOrderMap.forEach((key, value) -> System.out.println(key + ": " + value));

// Access some pages (moves them to end)
accessOrderMap.get("page2"); // About Page accessed
accessOrderMap.get("page1"); // Home Page accessed

System.out.println("\nAfter accessing page2 and page1:");
accessOrderMap.forEach((key, value) -> System.out.println(key + ": " + value));

// Update a page (moves to end)
accessOrderMap.put("page3", "Updated Contact Page");

System.out.println("\nAfter updating page3:");
accessOrderMap.forEach((key, value) -> System.out.println(key + ": " + value));

// Demonstrate LRU behavior
class SimpleLRUCache<K, V> extends LinkedHashMap<K, V> {
    private final int maxSize;
    
    public SimpleLRUCache(int maxSize) {
        super(16, 0.75f, true); // access-order = true
        this.maxSize = maxSize;
    }
    
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > maxSize;
    }
}

// Use LRU cache
SimpleLRUCache<String, String> cache = new SimpleLRUCache<>(3);
cache.put("A", "Value A");
cache.put("B", "Value B");
cache.put("C", "Value C");
System.out.println("\nLRU Cache after adding A, B, C: " + cache);

cache.get("A"); // Access A (moves to end)
cache.put("D", "Value D"); // Should remove B (least recently used)
System.out.println("After accessing A and adding D: " + cache);

Output:

Initial order:

page1: Home Page

page2: About Page

page3: Contact Page

page4: Products Page


After accessing page2 and page1:

page3: Contact Page

page4: Products Page

page2: About Page

page1: Home Page


LRU Cache after adding A, B, C: {A=Value A, B=Value B, C=Value C}

After accessing A and adding D: {C=Value C, A=Value A, D=Value D}

🔹 LinkedHashMap vs HashMap vs TreeMap

Comparison of different Map implementations:

// Demonstrate differences between Map implementations
String[] keys = {"Zebra", "Apple", "Banana", "Cherry"};
int[] values = {4, 1, 2, 3};

// HashMap - No guaranteed order
HashMap<String, Integer> hashMap = new HashMap<>();
for (int i = 0; i < keys.length; i++) {
    hashMap.put(keys[i], values[i]);
}
System.out.println("HashMap (random order): " + hashMap);

// LinkedHashMap - Insertion order
LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>();
for (int i = 0; i < keys.length; i++) {
    linkedHashMap.put(keys[i], values[i]);
}
System.out.println("LinkedHashMap (insertion order): " + linkedHashMap);

// TreeMap - Sorted order
TreeMap<String, Integer> treeMap = new TreeMap<>();
for (int i = 0; i < keys.length; i++) {
    treeMap.put(keys[i], values[i]);
}
System.out.println("TreeMap (sorted order): " + treeMap);

// Performance comparison
System.out.println("\nPerformance Characteristics:");
System.out.println("HashMap:       O(1) get/put, no order guarantee");
System.out.println("LinkedHashMap: O(1) get/put, maintains insertion order");
System.out.println("TreeMap:       O(log n) get/put, maintains sorted order");

// Memory usage
System.out.println("\nMemory Usage:");
System.out.println("HashMap:       Lowest memory usage");
System.out.println("LinkedHashMap: Extra memory for linked list pointers");
System.out.println("TreeMap:       Extra memory for tree structure");

Output:

HashMap (random order): {Apple=1, Cherry=3, Zebra=4, Banana=2}

LinkedHashMap (insertion order): {Zebra=4, Apple=1, Banana=2, Cherry=3}

TreeMap (sorted order): {Apple=1, Banana=2, Cherry=3, Zebra=4}


Performance Characteristics:

HashMap: O(1) get/put, no order guarantee

LinkedHashMap: O(1) get/put, maintains insertion order

TreeMap: O(log n) get/put, maintains sorted order

🧠 Test Your Knowledge

What order does LinkedHashMap maintain by default?