LinkedHashMap in Java

Naveen AnamaneniUpdated · 5 min read

LinkedHashMap in Java is a class that extends HashMap and keeps its entries in a predictable order. By default, the order is insertion order: entries come out in the order their keys were first added. It can also be switched to access order, where every read moves an entry to the end. Inside, it is a HashMap plus a doubly linked list running through all the entries. In this lesson, you will learn how to use LinkedHashMap and how to build an LRU cache with it, a classic interview problem.

Declaration

Declaration
public class LinkedHashMap<K, V> extends HashMap<K, V>
        implements SequencedMap<K, V>

Features of LinkedHashMap

  • Ordered: insertion order by default, or access order if requested.
  • Fast: the same O(1) average operations as HashMap.
  • One null key and many null values.
  • Putting an existing key again doesn't change its position in insertion-order mode.
  • Sequenced (Java 21): firstEntry, lastEntry, pollFirstEntry, reversed and more.
  • Not synchronized.

Constructors

ConstructorDescription
LinkedHashMap()It creates an empty map in insertion order.
LinkedHashMap(int capacity, float loadFactor, boolean accessOrder)It creates an empty map; accessOrder = true orders entries by most recent access.
LinkedHashMap(Map<? extends K, ? extends V> m)It creates a map with the pairs of another map, in that map's order.

Example: Insertion Order

Let's see an example comparing it with the order rules.

LinkedOrder.java▶ Try it
import java.util.LinkedHashMap;
import java.util.Map;
 
public class LinkedOrder {
    public static void main(String[] args) {
        Map<String, Integer> marks = new LinkedHashMap<>();
        marks.put("Srihitha", 78);
        marks.put("Navika", 91);
        marks.put("Advitha", 85);
        System.out.println(marks);
 
        marks.put("Srihitha", 88);
        System.out.println(marks);
    }
}
Output
{Srihitha=78, Navika=91, Advitha=85}
{Srihitha=88, Navika=91, Advitha=85}

Explanation: Entries print in the order they were added. Updating Srihitha's mark changes the value but keeps Srihitha in first place.

Access Order

With accessOrder = true, every get or put of a key moves that entry to the end. The first entry is then always the least recently used one:

AccessOrder.java▶ Try it
import java.util.LinkedHashMap;
import java.util.Map;
 
public class AccessOrder {
    public static void main(String[] args) {
        Map<String, Integer> m = new LinkedHashMap<>(16, 0.75f, true);
        m.put("Navika", 1);
        m.put("Srihitha", 2);
        m.put("Advitha", 3);
        System.out.println(m);
 
        m.get("Navika");
        System.out.println(m);
    }
}
Output
{Navika=1, Srihitha=2, Advitha=3}
{Srihitha=2, Advitha=3, Navika=1}

Explanation: Reading Navika moved that entry to the end. Srihitha, untouched for longest, is now first.

The Checkpoint: An LRU Cache

An LRU (least recently used) cache holds a fixed number of entries. When it is full and a new entry arrives, it removes the entry that was used longest ago. LinkedHashMap makes this almost free: use access order, and override removeEldestEntry, which the map calls after every put.

Access moves an entry to the end; the eldest entry at the front is evicted
LruCache.java▶ Try it
import java.util.LinkedHashMap;
import java.util.Map;
 
public class LruCache<K, V> extends LinkedHashMap<K, V> {
    private final int capacity;
 
    public LruCache(int capacity) {
        super(16, 0.75f, true);
        this.capacity = capacity;
    }
 
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > capacity;
    }
 
    public static void main(String[] args) {
        LruCache<String, String> cache = new LruCache<>(3);
        cache.put("A", "page A");
        cache.put("B", "page B");
        cache.put("C", "page C");
        System.out.println(cache.keySet());
 
        cache.get("A");
        System.out.println("after get(A): " + cache.keySet());
 
        cache.put("D", "page D");
        System.out.println("after put(D): " + cache.keySet());
    }
}
Output
[A, B, C]
after get(A): [B, C, A]
after put(D): [C, A, D]

Explanation: super(16, 0.75f, true) turns on access order. Reading A moved it to the end, so B became the least recently used. When D was added, the size became 4, removeEldestEntry returned true, and the map removed B, its eldest entry.

Common Mistakes

Forgetting the third constructor argument. Without true, the map stays in insertion order and the "LRU" cache evicts the oldest inserted entry instead.

Expecting put of an existing key to move it in insertion-order mode. Only access-order mode moves entries.

Iterating an access-order map with get calls inside the loop. Each get reorders the map and throws ConcurrentModificationException.

Interview Corner

How do you implement an LRU cache in Java?

Extend LinkedHashMap with the constructor super(capacity, 0.75f, true) to enable access order, so every access moves the entry to the end. Override removeEldestEntry(Map.Entry eldest) to return size() > capacity; the map calls it after each insertion and removes the first (least recently used) entry when it returns true. get and put remain O(1).

What is the difference between HashMap and LinkedHashMap?

Both are hash-table maps with O(1) average operations. HashMap has no guaranteed order. LinkedHashMap also keeps a doubly linked list through its entries, so it iterates in insertion order or, if constructed with accessOrder = true, in order of most recent access. It uses a little more memory and supports removeEldestEntry for cache eviction.

Practice

  1. Easy: Store the first five countries a user enters in a LinkedHashMap from country to capital, and print them in input order.
  2. Harder: Change the LRU cache so it prints a message naming the evicted key every time an entry is removed.

Quick check: LinkedHashMap

4 questions
1What order does a LinkedHashMap use by default?
2How do you turn on access order?
3Which method decides when an LRU cache evicts?
4In access-order mode, where does an entry go after get?

Key Takeaways

Was this tutorial helpful?

Lesson 286 of 482