How do I use LinkedHashMap for predictable iteration order?

In Java, a LinkedHashMap is a subtype of HashMap that maintains a predictable iteration order. It uses a doubly linked list to store the entries in insertion order (or, optionally, access order). Here’s how you can use LinkedHashMap for predictable iteration order:

1. Maintaining Insertion Order

By default, a LinkedHashMap iterates its entries in the order they were inserted. This is useful when you want to retrieve elements in the same order you added them.

Here’s an example:

package org.kodejava.util;

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapExample {
    public static void main(String[] args) {
        // Creating LinkedHashMap
        Map<String, Integer> map = new LinkedHashMap<>();

        // Adding elements (insertion order)
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);
        map.put("Four", 4);

        // Iterating through the map
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " => " + entry.getValue());
        }
    }
}

Output:

One => 1
Two => 2
Three => 3
Four => 4

In this example, the elements are iterated in the same order they were inserted.


2. Maintaining Access Order

You can configure a LinkedHashMap to maintain access order, which means it reorders entries based on the most recent access. To enable access order, you must use the constructor that takes a boolean parameter for accessOrder.

Here’s an example:

package org.kodejava.util;

import java.util.LinkedHashMap;
import java.util.Map;

public class AccessOrderExample {
    public static void main(String[] args) {
        // Creating LinkedHashMap with access-order
        Map<String, Integer> map = new LinkedHashMap<>(16, 0.75f, true);

        // Adding elements
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);

        // Accessing some elements
        map.get("One");  // Access "One"
        map.get("Three"); // Access "Three"

        // Iterating through the map
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " => " + entry.getValue());
        }
    }
}

Output:

Two => 2
One => 1
Three => 3

In this case:

  • Initially, the insertion order was One, Two, Three.
  • After accessing One and Three, they were moved to the end, making Two the first in the iteration order.

3. Removing the Oldest Entry with Access Order

If needed, you can use a LinkedHashMap in combination with its removeEldestEntry method to automatically remove the oldest entry (e.g., implementing a cache).

Here’s how:

package org.kodejava.util;

import java.util.LinkedHashMap;
import java.util.Map;

public class RemoveEldestExample {
    public static void main(String[] args) {
        // Create LinkedHashMap with override for removeEldestEntry
        LinkedHashMap<String, Integer> map = new LinkedHashMap<>(3, 0.75f, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
                return size() > 3; // Remove oldest if size > 3
            }
        };

        // Adding elements
        map.put("One", 1);
        map.put("Two", 2);
        map.put("Three", 3);
        map.put("Four", 4); // "One" will be removed here

        // Accessing some elements
        map.get("Two");
        map.put("Five", 5); // "Three" will be removed here

        // Iterating through the map
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " => " + entry.getValue());
        }
    }
}

Output:

Four => 4
Two => 2
Five => 5

Explanation:

  1. The map was set to remove the eldest (first) entry when its size exceeds 3.
  2. When "Four" was added, "One" was removed because the size limit was exceeded.
  3. When "Five" was added, "Three" was removed, as it was now the eldest entry after accessing "Two".

Summary of Key Points:

  1. Insertion Order: By default, the iteration order matches the insertion order.
  2. Access Order: Can be enabled using the LinkedHashMap constructor with accessOrder = true.
  3. Custom Behavior: Override the removeEldestEntry method to create a fixed-size cache or similar functionality.

LinkedHashMap is handy when you need consistent iteration order (e.g., for caches, ordering-sensitive collections).