HashMap in java

Previous
Next

HashMap is hash table based implementation of Map interface. It stores entry in key-value pairs. It maps keys to values. It is one of the most used Collection.

Java HashMap

HashMap

  1. HashMap implements Map an interface that maps a key to value.
  2. It is not synchronized and is not thread-safe.
  3. Duplicate keys are not allowed
  4. One null key and multiple null values are allowed
  5. It is the unordered collection and does not give a guarantee for any specific order of elements.

HashMap

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 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 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.

  1. remove(Object key): It removes key from HashMap
  2. remove(Object key,Object value): It removes key if value is same as 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 HashMap
put(): Put value into the HashMap
isEmpty: Check if HashMap is empty.
containsKey(): Check if key present is HashMap
containsValue(): Check if value exists in HashMap
size(): Check size of the HashMap
clear(): To remove all elements from Hashmap
clone(): It creates 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 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.

  1. Create a HashMap which will contain character to count mapping.
  2. Iterate over String character by character
  3. If Character is not present in map, then count should be 1
  4. 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, 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

  1. Iterating over HashMap using keyset()
  2. Iterating over HashMap using keyset() with foreach() and lambda expression[ java 8]
  3. Iterating over HashMap using foreach() and lambda expression [java 8]
  4. Iterating over HashMap’s entrySet() using iterator
  5. Iterating over HashMap’s entrySet() using foreach() and lambda expression [java 8]
  6. 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 above program, you will get below output

—————————–
Iterating HashMap Using keySet() and for each loop
Country: Japan | population:3000 and Capital:Tokyo
Country: India | population:10000 and Capital:Delhi
Country: Russia | population:4000 and Capital:Moscow
Country: France | population:5000 and Capital:Paris
—————————–

Sort HashMap in java

By Keys

We can sort keys in HashMap by using TreeMap. We just need to pass a HashMap to the constructor of TreeMap.

By Values

We need to follow below steps to sort HashMap by values.

  1. Get entrySet() from HashMap
  2. convert entrySet to List
  3. Sort the list with the help of Comparator
  4. Iterate over list and put the Entry object in LinkedHashMap

Let’s write an example to sort HashMap by keys and values. We will create a class named Vehicle and will use it as Key in HashMap and value will be the owner of the Vehicle.

Create a class named Vehicle.java

Please note that we have implemented comparable interface here which compares two vehicle by its name. This Comparable will be used to sort it by Keys while constructing TreeMap.
Create a class named HashMapSortMain.java

Output:

Sorted TreeMap by vehicle name: {Vehicle name: Bike|Max speed: 150=Mary, Vehicle name: Car|Max speed: 150=John, Vehicle name: Jeep|Max speed: 180=Harry, Vehicle name: Truck|Max speed: 130=Chris}Sorted Map by owner name: {Vehicle name: Truck|Max speed: 130=Chris, Vehicle name: Jeep|Max speed: 180=Harry, Vehicle name: Car|Max speed: 150=John, Vehicle name: Bike|Max speed: 150=Mary}

If you don’t understand the syntax of lambda expression which we have used above to sort List of Entry objects,then you need to go through Lambda Expression in Java 8.

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 increment time for both counter by 1 and we are using ExecuterService to submit it 100 times.

Let’s run the program and check 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:

  1. Collections.synchronizedMap
  2. 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 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 separate post, so I have written 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 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 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

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.
Previous
Next

Add Comment