Java LinkedHashMap


The LinkedHashMap class in Java is an implementation of the Map interface that combines the features of a hash table and a linked list. What makes LinkedHashMap different from other Map implementations like HashMap is its ability to maintain the insertion order of the keys. This feature makes it ideal for scenarios where the order in which elements are added to the map matters.

In this article, we'll explore the key features of LinkedHashMap, its performance characteristics, and how to use it effectively in your Java applications. By the end, you'll understand when and why you might choose LinkedHashMap over other Map implementations like HashMap and TreeMap.


What is LinkedHashMap in Java?

LinkedHashMap is a class that implements the Map interface and is part of the java.util package. It maintains a doubly linked list that runs through all of its entries, ensuring that the iteration order is predictable, which is the order in which the elements were inserted.

Key features of LinkedHashMap:

  • Insertion Order: The keys in a LinkedHashMap are ordered according to the order in which they were inserted. This is unlike HashMap, which has no guaranteed order.
  • Allows Null: Like HashMap, LinkedHashMap allows one null key and multiple null values.
  • Performance: The performance of LinkedHashMap is generally similar to HashMap for operations like put() and get(), but with a slight overhead due to maintaining the linked list for ordering.
  • Thread-Unsafe: Like HashMap, LinkedHashMap is not synchronized and is not thread-safe by default.

Constructor of LinkedHashMap

The LinkedHashMap class provides a few constructors for different use cases:

LinkedHashMap()                               // Creates an empty map with the default initial capacity (16) and load factor (0.75).
LinkedHashMap(int initialCapacity)            // Creates a map with the specified initial capacity.
LinkedHashMap(int initialCapacity, float loadFactor)  // Creates a map with the specified initial capacity and load factor.
LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)  // Creates a map with specified initial capacity, load factor, and access order.
  • initialCapacity: The initial number of buckets in the map. The default is 16.
  • loadFactor: The load factor is the threshold at which the map will resize. The default is 0.75.
  • accessOrder: If true, the order of the map is based on the order of access, meaning the least recently accessed elements are moved to the end of the map. If false (default), the map maintains insertion order.

Key Methods of LinkedHashMap

Here are some commonly used methods of the LinkedHashMap class:

  • put(K key, V value): Adds a key-value pair to the map. If the key already exists, it updates the value.

    map.put("apple", 1);
    
  • get(Object key): Retrieves the value associated with the specified key.

    int value = map.get("apple");  // Returns 1
    
  • containsKey(Object key): Checks if the map contains the specified key.

    boolean exists = map.containsKey("apple");  // Returns true
    
  • remove(Object key): Removes the key-value pair associated with the specified key.

    map.remove("apple");  // Removes the entry with key "apple"
    
  • keySet(): Returns a set view of all the keys in the map.

    Set<String> keys = map.keySet();  // Returns a Set of all keys
    
  • values(): Returns a collection view of all the values in the map.

    Collection<Integer> values = map.values();  // Returns a Collection of all values
    
  • entrySet(): Returns a set view of all the key-value pairs (entries) in the map.

    Set<Map.Entry<String, Integer>> entries = map.entrySet();  // Returns a Set of Map.Entry
    
  • clear(): Removes all key-value pairs from the map.

    map.clear();  // Removes all entries from the map
    

Example 1: Using LinkedHashMap to Preserve Insertion Order

Below is an example showing how a LinkedHashMap maintains insertion order:

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

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

        // Add some key-value pairs to the map
        map.put("apple", 1);
        map.put("banana", 2);
        map.put("orange", 3);

        // Retrieve values using keys
        System.out.println("Value for 'apple': " + map.get("apple"));  // Output: 1
        System.out.println("Value for 'banana': " + map.get("banana"));  // Output: 2

        // Print all entries in the map
        System.out.println("Entries in the map (in insertion order): ");
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " -> " + entry.getValue());
        }
    }
}

Output:

Value for 'apple': 1
Value for 'banana': 2
Entries in the map (in insertion order): 
apple -> 1
banana -> 2
orange -> 3

In this example, we see that LinkedHashMap preserves the order of insertion, ensuring that elements are retrieved in the same order they were added.


Example 2: LinkedHashMap with Access Order

Here’s an example of LinkedHashMap with access order enabled:

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

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

        // Add some key-value pairs to the map
        map.put("apple", 1);
        map.put("banana", 2);
        map.put("orange", 3);

        // Access some elements to change the access order
        map.get("banana");
        map.get("orange");

        // Print all entries in the map (entries should now be ordered by access order)
        System.out.println("Entries in the map (in access order): ");
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " -> " + entry.getValue());
        }
    }
}

Output:

Entries in the map (in access order): 
apple -> 1
orange -> 3
banana -> 2

In this example, the LinkedHashMap is constructed with accessOrder set to true. When we access "banana" and "orange", their positions are moved to the end of the map, reflecting the access order.


Performance Considerations

  • Time Complexity: The average time complexity for get(), put(), and remove() operations is O(1) in most cases. However, there is a slight overhead for maintaining the linked list that keeps the order.
  • Iteration: Iterating through a LinkedHashMap is more predictable than iterating through a HashMap due to the maintained order (either insertion order or access order).
  • Thread-Safety: LinkedHashMap is not synchronized. If you need thread safety, consider using ConcurrentHashMap or synchronizing access manually.

When to Use LinkedHashMap

You should consider using LinkedHashMap when:

  1. You need to maintain the order of insertion or the order of access (for example, for an LRU cache).
  2. You want to iterate over the entries in a predictable order (either insertion order or access order).
  3. You require a hash-based map with a predictable iteration order.