LinkedHashMap is a Hashtable and linked list-based implementation of Map interface, with predictable insertion order. It maintains double linked list of all its entries, that’s how it differs from HashMap.
Table of Contents
Java LinkedHashMap
Some points about LinkedHashMap
- LinkedHashMap implements Map interface and extends HashMap class.
- LinkedHashMap maintains insertion order, so when you will be able to access elements in the order they were inserted like ArrayList.
- LinkedHashMap maintains doubly Linked list to maintain insertion order.
- It is not synchronized and is not thread-safe.
- Duplicate keys are not allowed
- One
null
key and multiplenull
values are allowed
Did you notice LinkedHashMap implements Map interface even if AbstractMap and HashMap already implements it?
Yes, Just to make things more obvious, LinkedHashMap implements Map interface again and there is nothing wrong in implementing interface again. You don’t have to go through class Hierarchy to find it out that LinkedHashMap implements Map interface.
LinkedHashMap Constructors
Java LinkedHashMap class has five constructors
public LinkedHashMap()
: This is the default constructor and used mostly. It creates an empty LinkedHashMap with default initial capacity of 16 and load factor 0.75.
public LinkedHashMap(int initialCapacity)
: This constructor is used to specify the initial capacity of LinkedHashMap and default load factor 0.75.
public LinkedHashMap(int initialCapacity,float loadFactor)
: This constructor is used to specify initial capacity of the LinkedHashMap and load factor. In most of the scenarios, you should avoid using this constructor unless you are sure about this as load factor 0.75 provides a good tradeoff between time and space.
public LinkedHashMap(Map<? extends K,? extends V> m)
: This constructor is used when you want to create LinkedHashMap from some other Map such as TreeMap or HashMap.
public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder)
: This constructor is used to specify initial capacity, load factor and access order of HashMap. If we pass access order as true, then it will list entries based on access order.
Add key-value pairs to LinkedHashMap
We can use put()
method to add entries to LinkedHashMap
similar to HashMap.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package org.arpit.java2blog; import java.util.LinkedHashMap; import java.util.Map; public class LinkedHashMapEntriesMain { public static void main(String[] args) { Map<Integer, String> studentMap = new LinkedHashMap<Integer, String>(); // Putting key-values pairs in LinkedHashMap studentMap.put(1, "Arvind"); studentMap.put(2, "Andy"); studentMap.put(3, "Mohan"); studentMap.put(4, "Virat"); System.out.println(studentMap); } } |
When you run above program, you will get below output
As you can see, all the entries are printed in insertion order as expected.
What if you want to add entries only if it is not already present in LinkedHashMap?
You can use putIfAbsent()
the method in this scenario.
💡 Did you know?
After Java 7, you can use diamond operator(
<>
) to initialize Map.
You can change
Map<Integer, String> studentMap = new LinkedHashMap<Integer, String>();
to
Map<Integer, String> studentMap = new LinkedHashMap<>();
Remove entries from LinkedHashMap
There are two ways to remove entries in LinkedHashMap.
remove(Object key)
: It removes key from LinkedHashMapremove(Object key,Object value)
: It removes key if value is same as passed parameter value.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
package org.arpit.java2blog.HashMap; package org.arpit.java2blog; import java.util.LinkedHashMap; import java.util.Map; public class LinkedHashMapRemoveMain { public static void main(String[] args) { Map<String, Integer> travelFareMap = new LinkedHashMap<String, Integer>(); // Putting key-values pairs in LinkedHashMap travelFareMap.put("Bus", 120); travelFareMap.put("Car", 2200); travelFareMap.put("Rail", 680); travelFareMap.put("Flight", 4000); System.out.println(travelFareMap); // Remove car key Integer fareCar = travelFareMap.remove("Car"); System.out.println("==============================="); System.out.println("Vehicle Car with fare "+fareCar+" removed from HashMap"); System.out.println(travelFareMap); System.out.println("================================"); // Remove Rail if fate is 800 boolean isCarRemoved = travelFareMap.remove("Rail",800); // Rail key won't be removed as associated value is 680 System.out.println("Did car removed from LinkedHashMap: "+isCarRemoved); System.out.println(travelFareMap); System.out.println("==============================="); // Remove Flight if fare is 4000 boolean isFlightRemoved = travelFareMap.remove("Flight",4000); // flight key will be removed as associated value is 4000 System.out.println("Did Flight removed from LinkedHashMap: "+isFlightRemoved); System.out.println(travelFareMap); System.out.println("==============================="); } } |
Output:
===============================
Vehicle Car with fare 2200 removed from HashMap
{Bus=120, Rail=680, Flight=4000}
================================
Did car removed from LinkedHashMap: false
{Bus=120, Rail=680, Flight=4000}
===============================
Did Flight removed from LinkedHashMap: true
{Bus=120, Rail=680}
===============================
Important LinkedHashMap methods
get()
: Retrieve value from the LinkedHashMap
put()
: Put value into the LinkedHashMap
isEmpty
: Check if LinkedHashMap is empty.
containsKey()
: Check if key present is LinkedHashMap
containsValue()
: Check if value exists in LinkedHashMap
size()
: Check size of the LinkedHashMap
clear()
: To remove all elements from LinkedHashMap
clone()
: It creates shallow copy of LinkedHashMap.
Here is an example to cover these methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
package org.arpit.java2blog; import java.util.LinkedHashMap; import java.util.Map; public class LinkedHashMapMethodsMain { public static void main(String[] args) { Map<String, String> profDeptmap = new LinkedHashMap<>(); //check if map is empty boolean empty = profDeptmap.isEmpty(); System.out.println("is profDeptmap empty: "+empty); // Putting key-values pairs in HashMap profDeptmap.put("Arvind","Chemistry"); profDeptmap.put("Venkat", "Physics"); profDeptmap.put("Mary", "History"); profDeptmap.put("David","Maths"); System.out.println(profDeptmap); //check size of map System.out.println("size of profDeptmap: "+profDeptmap.size()); // get value from LinkedHashMap System.out.println("Venkat's department: "+profDeptmap.get("Venkat")); // Hamlet department will be null as we don't have key as "Hamlet" System.out.println("Hamlet's department: "+profDeptmap.get("Hamlet")); if(profDeptmap.containsKey("David")) { System.out.println("profDeptmap has David as key"); } if(profDeptmap.containsValue("History")) { System.out.println("profDeptmap has History as value"); } // Removing all entries from Map profDeptmap.clear(); System.out.println(profDeptmap); } } |
Output:
{Arvind=Chemistry, Venkat=Physics, Mary=History, David=Maths}
size of profDeptmap: 4
Venkat’s department: Physics
Hamlet’s department: null
profDeptmap has David as key
profDeptmap has History as value
{}
Get entrySet(), keySet() and values() from LinkedHashMap
entrySet()
entrySet()
: As HashMap stores key value pair in form of Entry
, we can retrieve entrySet() by calling map.entrySet()
keySet()
keySet()
: Provides a set of keys.
values()
values()
: Provides a collection of values.
Here is the example for the same.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
package org.arpit.java2blog; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class LinkedHashMapMain { public static void main(String[] args) { Map<Integer, String> studentIDNameMap = new LinkedHashMap<>(); // Putting key-values pairs in LinkedHashMap studentIDNameMap.put(1001,"Andrew"); studentIDNameMap.put(1002, "Martin"); studentIDNameMap.put(1003, "Sameer"); studentIDNameMap.put(1004,"Venkat"); // get entrySet Set<Entry<Integer, String>> entrySet = studentIDNameMap.entrySet(); System.out.println("EntrySet: "+entrySet); // get keySet Set<Integer> keySet = studentIDNameMap.keySet(); System.out.println("keySet: "+keySet); // get values Collection<String> values = studentIDNameMap.values(); System.out.println("values: "+values); } } |
Output:
As you can see, all the pairs or values are in insertion order.
Iterate over LinkedHashMap
There are many ways to iterate over LinkedHashMap
- Iterating over LinkedHashMap using
keyset()
- Iterating over LinkedHashMap using
keyset()
with foreach() and lambda expression( java 8) - Iterating over LinkedHashMap using foreach()and lambda expression (java 8)
- Iterating over LinkedHashMap’s
entrySet()
usingiterator
- Iterating over LinkedHashMap’s
entrySet()
using foreach() and lambda expression [java 8] - Iterating over LinkedHashMap’s
entrySet()
using foreach loop
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
package org.arpit.java2blog; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; public class LinkedHashMapIterationMain { public static void main(String[] args) { Map<String, Long> countryPopulationMap = new LinkedHashMap<>(); // Putting key-values pairs in LinkedHashMap countryPopulationMap.put("India",13000L); countryPopulationMap.put("China", 15000L); countryPopulationMap.put("Germany", 9000L); countryPopulationMap.put("France",7000L); System.out.println("========================================================="); System.out.println("Iterating over LinkedHashMap with foreach and lambda:"); countryPopulationMap.forEach((country,population) -> { System.out.println(country+" --> "+population); } ); System.out.println("========================================================="); System.out.println("Iterating over LinkedHashMap using keyset() with foreach loop:"); for(String user:countryPopulationMap.keySet()) { System.out.println(user+" --> "+countryPopulationMap.get(user)); } System.out.println("========================================================="); System.out.println("Iterating over LinkedHashMap keyset() with foreach and lambda:"); countryPopulationMap.keySet().forEach((user) -> { System.out.println(user+" --> "+countryPopulationMap.get(user)); } ); System.out.println("========================================================="); System.out.println("Iterating over LinkedHashMap entrySet with iterator"); Iterator<Entry<String, Long>> iterator = countryPopulationMap.entrySet().iterator(); while(iterator.hasNext()) { Entry<String, Long> next = iterator.next(); System.out.println(next.getKey()+" --> "+next.getValue()); } System.out.println("========================================================="); System.out.println("Iterating over LinkedHashMap's entrySet with foreach and lambda"); countryPopulationMap.entrySet().forEach((entry) -> { System.out.println(entry.getKey()+" --> "+entry.getValue()); } ); System.out.println("========================================================="); System.out.println("Iterating over LinkedHashMap's entrySet with foreach loop"); for(Map.Entry<String, Long> entry:countryPopulationMap.entrySet()) { System.out.println(entry.getKey()+" --> "+entry.getValue()); } } } |
Output:
Iterating over LinkedHashMap with foreach and lambda:
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap using keyset() with foreach loop:
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap keyset() with foreach and lambda:
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap entrySet with iterator
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap’s entrySet with foreach and lambda
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
=========================================================
Iterating over LinkedHashMap’s entrySet with foreach loop
India –> 13000
China –> 15000
Germany –> 9000
France –> 7000
Access order LinkedHashMap
In case, if you want to retrieve entries from LinkedHashMap in access order, you can use LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
constructor.
Let me provide you realtime usecase of LinkedHashMap with access order.
You can use LinkedHashMap with access order to implement LRU cache.
Create a class named LRULHCache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
package org.arpit.java2blog; import java.util.LinkedHashMap; import java.util.Map; class LRULHCache<K,V> { private LinkedHashMap<K, V> map; public LRULHCache(int capacity) { map = new LinkedHashMap<K, V>(capacity, 0.75f, true) { protected boolean removeEldestEntry(Map.Entry eldest) { return size() > capacity; } }; } // This method works in O(1) public V get(K key) { return map.get(key); } // This method works in O(1) public void set(K key, V value) { map.put(key, value); } @Override public String toString() { return "LinkedHashMap: "+map.toString(); } } public class LinkedHashMapAccessOrderMain { public static void main(String[] args) { LRULHCache<Integer,Integer> lruLHCache = new LRULHCache<>(2); lruLHCache.set(2, 12000); lruLHCache.set(40, 70000); System.out.println(lruLHCache); // renews the entry System.out.println(lruLHCache.get(2)); System.out.println(lruLHCache); lruLHCache.set(20, 70000); System.out.println(lruLHCache); System.out.println(lruLHCache.get(2)); System.out.println(lruLHCache); System.out.println(lruLHCache.get(40)); } } |
Output
12000
LinkedHashMap: {40=70000, 2=12000}
LinkedHashMap: {2=12000, 20=70000}
12000
LinkedHashMap: {20=70000, 2=12000}
null
As you can see we have created LRULHCache with capacity 2 and once we call get()
, LinkedHashMap is renewed with that key.
Is LinkedHashMap thread-safe?
LinkedHashMap is not thread-safe by default and it can give non-deterministic results in case of a multithreaded environment.
If multiple threads try to access LinkedHashMap and one of them does the structural modification, then it should be externally synchronized.
Best way to do this at LinkedHashMap creation time.
1 2 3 |
Map m=Collections.synchronizedMap(new LinkedHashMap()); |
I have already provided an example for HashMap thread safety, since same example is applicable for LinkedHashMap, you can go through this.
Conclusion
You have learned about basics of LinkedHashMap, how to create a LinkedHashMap and add key-value pairs to it, important LinkedHashMap methods, how to iterate over LinkedHashMap and thread safety issues with LinkedHashMap and how to synchronized a LinkedHashMap.
That’s all about HashMap in java.