A Comprehensive Guide to HashMap in Java
HashMap is a hash table based implementation of Map
interface. It stores an entry in key-value pairs. It maps keys to values. It is one of the most used Collection.
Java HashMap
HashMap
implementsMap
an interface that maps a key to value.- It is not synchronized and is not thread-safe.
- Duplicate keys are not allowed
- One
null
key and multiplenull
values are allowed - It is the unordered collection and does not give a guarantee for any specific order of elements.
Did you notice HashMap implements Map interface even if AbstractMap already implements it?
Yes, Just to make things more obvious, HashMap 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 HashMap implements Map interface.
HashMap Constructors
Java HashMap class has four constructors
public HashMap()
: This is the default constructor and used mostly. It creates an empty HashMap with a default initial capacity of 16 and load factor 0.75.
public HashMap(int initialCapacity)
: This constructor is used to specify the initial capacity of HashMap and default load factor 0.75.
public HashMap(int initialCapacity,float loadFactor)
: This constructor is used to specify the initial capacity of the HashMap 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 HashMap(Map<? extends K,? extends V> m)
: This constructor is used when you want to create HashMap from some other Map such as TreeMap or LinkedHashMap.
Add key-value pairs to HashMap
We can use put()
method to add entries to HashMap
.
Example:
When you run above program, you will get below output
{1=Arpit, 2=John, 3=Martin, 4=Vaibhav}
What if you want to add entries only if it is not already present in HashMap?
You can use putIfAbsent()
the method in this scenario.
Remove entries from HashMap
There are two ways to remove entries in HashMap.
remove(Object key)
: It removes key from HashMapremove(Object key,Object value)
: It removes key if the value is the same as the passed parameter value.
Output:
{Car=220, Activa=140, Truck=160, Bike=120}
===============================
Vehicle Truck with max speed 160 removed from HashMap
{Car=220, Activa=140, Bike=120}
================================
Did car removed from HashMap: false
{Car=220, Activa=140, Bike=120}
===============================
Did activa removed from HashMap: true
{Car=220, Bike=120}
===============================
Important HashMap methods
get()
: Retrieve value from the HashMapput()
: Put value into the HashMapisEmpty
: Check if HashMap is empty.containsKey()
: Check if key present is HashMapcontainsValue()
: Check if the value exists in HashMapsize()
: Check size of the HashMapclear()
: To remove all elements from Hashmapclone()
: It creates a shallow copy of HashMap.
Here is an example to cover these methods.
Output:
is employeeDeptmap empty: true
{Arpit=Tech, John=Sales, Martin=HR, Vaibhav=Tech}
size of employeeDeptmap: 4
Martin’s department: HR
Robin’s department: null
employeeDeptmap has John as key
employeeDeptmap has Sales as value
{}
Write declarative style code with HashMap
Java 8’s Map interface introduced new methods such as compute(), computeIfPresent() and computeIfAbsent()
which help you write code using lambda expressions.
compute()
Let’s say you have a HashMap of team and no. of goal as below.
Now you want to add 1 goal to team1
and generally, you do it as follow.
Instead, you can easily do it with compute as below.
So whenever you want to apply mappings based on key, value pair then compute should be used.
computeIfPresent()
computeIfPresent recomputes the value if specified key is present and value is not null.
You might have written code like below before:
You can rewrite this with computeIfPresent
as below
If function returns null, then key will be removed from HashMap.
computeIfAbsent()
computeIfAbsent recomputes the value if the specified key is not present and function does not return null.
You might have written code like below before:
You can rewrite this with computeIfAbsent
as below
If key is already present in map, then nothing will change.
Let’s see another example to rewrite HashMap code in a declarative style.
Problem: You want to find the frequency of each character in String.
You might have written the program in a trivial way as below.
Output:
{a=2, b=1, s=2, t=1, v=1, g=1, h=1, i=2, j=1, l=1, o=1}
Above program uses simple logic to count frequency of each character in String.
- Create a HashMap which will contain the character to count mapping.
- Iterate over String character by character
- If Character is not present in map, then count should be 1
- If Character is already present in map, then increment its count by 1
Let’s rewrite this logic using computeIfPresent
and computeIfAbesent
methods.
Output:
{a=2, b=1, s=2, t=1, v=1, g=1, h=1, i=2, j=1, l=1, o=1}
As you can see, the logic looks quite readable in case of computeIfPresent
and computeIfAbesent
methods.
Get entrySet(), keySet() and values() from HashMap
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.
Output:
EntrySet: [101=Andy, 102=Mary, 103=Sam, 104=Sandy]
keySet: [101, 102, 103, 104]
values: [Andy, Mary, Sam, Sandy]
Iterate over HashMap
There are many ways to iterate over HashMap
- Iterating over HashMap using
keyset()
- Iterating over HashMap using
keyset()
with foreach() and lambda expression[ java 8] - Iterating over HashMap using foreach() and lambda expression [java 8]
- Iterating over HashMap’s
entrySet()
usingiterator
- Iterating over HashMap’s
entrySet()
using foreach() and lambda expression [java 8] - Iterating over HashMap’s
entrySet()
using foreach loop
Output:
=========================================================
Iterating over HashMap with foreach and lambda:
Anchit → India
Andy → USA
Roy → Germary
Mary → France
=========================================================
Iterating over HashMap using keyset() with foreach loop:
Anchit → India
Andy → USA
Roy → Germary
Mary → France
=========================================================
Iterating over HashMap’s keyset() with foreach and lambda:
Anchit → India
Andy → USA
Roy → Germary
Mary → France
=========================================================
Iterating over HashMap’s entrySet with iterator
Anchit → India
Andy → USA
Roy → Germary
Mary → France
=========================================================
Iterating over HashMap’s entrySet with foreach and lambda
Anchit → India
Andy → USA
Roy → Germary
Mary → France
=========================================================
Iterating over HashMap’s entrySet with foreach loop
Anchit → India
Andy → USA
Roy → Germary
Mary → France
Storing Custom objects as Key
You can store custom objects as Key in HashMap but you should implement hashcode and equals method, otherwise, it may not work as expected.
Create a class called Country.java
Create another class HashMapMain.java
When you run the above program, you will get below output
-----------------------------
Iterating HashMap Using keySet() and for each loop
Country:France and Capital:Paris
Country:Russia and Capital:Moscow
Country:Japan and Capital:Tokyo
Country:India and Capital:Delhi
-----------------------------
is HashMap thread-safe?
HashMap is not thread-safe by default and it can give non-deterministic results in case of a multithreaded environment.
Let’s demonstrate this with the help of an example:
I have put two entries in map with key as counter1 and counter2 and value as time 0 and 100 respectively. We have created a task which increments time for both counters by 1 and we are using ExecuterService to submit it 100 times.
Let’s run the program and check the output:
Time for Counter1: 95
Time for Counter2: 195
but our expected output should be
Time for Counter1: 100
Time for Counter2: 200
because we have submitted task 100 times and in each task execution, it calls incrementTime() and increases the time by 1.
Let’s run the program again.
Time for Counter1: 98
Time for Counter2: 197
It is different from the last execution and this is due to thread-safety issues in HashMap.
We can solve this thread safety issue in two ways:
- Collections.synchronizedMap
- ConcurrentHashmap
Collections.synchronizedMap
We can use Collections.synchronizedMap()
to make all operations of HashMap thread-safe and make incrementTime() method synchronized to solve above issue. incrementTime() should be also synchronized otherwise there will be atomicity issues.
Output:
Time for Counter1: 100
Time for Counter2: 200
As you can see, we are getting the correct output after using Collections.synchronizedMap()
and making incrementTime
synchronized.
ConcurrentHashMap
The disadvantage of using Collections.synchronizedMap() is that it locks whole hashmap object and which may cause performance issue but ConcurrentHashMap only locks part of the map and performs quite well in a multithreaded environment.
How HashMap works internally
This topic deserves a separate post, so I have written a complete tutorial on How HashMap works in java.
Java 8 HashMap update
To understand this change, you need to understand How HashMap works internally.Java 8 has introduced good performance improvement in case of too many hash collisions.
Before Java 7
If two objects have the same hashcode and are not equal, then both will be stored at the same bucket
with the help of the singly linked list. In case, there are too many hash collisions, then the performance of get()
and put()
may suffer.
In the worst case, if all keys have the same hashcode then get()
operation in HashMap may take O(n) time.
Java 8 Update
In Java 8, HashMap changes the linked list to a binary tree in case the number of elements reaches a certain threshold. With the help of this change, get() operation in HashMap may take O(log(n)) time in the worst case.
Java HashMap tutorial
- HashMap in java
- How HashMap works in java
- hash and indexfor method in HashMap
- hashcode and equals method in java
- How to sort HashMap by keys and values
- Difference between HashMap and HashSet
- Difference between HashMap and Hashtable
- How to iterate over HashMap
Conclusion
You have learned about basics of HashMap, how to create a HashMap and add key-value pairs to it, important HashMap methods, how to write declarative style code with HashMap, how to iterate over HashMap and thread safety issues with HashMap and how to synchronized a HashMap.
That’s all about HashMap in Java.