Merging two Maps in Java

Learn to merge or join two Maps in Java using Java Stream API and Plain Java ways. We’ll also cover how to resolve the duplicate key problem.

Overview

This is a quick and example oriented tutorial on Joining or Merging two HashMaps in Java. We will cover various ways of merging Maps offered by Java 8 Streams API as well as plain Java.

Java Maps stores elements based on the keys. Thus, when we reinsert an existing key, but with a different value the existing value gets replaced. However, during the merge the key collision may produce IllegalStateException. We’ll cover how we can provide a custom value mappers to avoid the exception.

Merging or Joining Two Maps

Before, we see different ways of combining key and value pairs between two Java Maps, let’s first create two Java Maps.

Here, we are using Java Map Inline Initialization two create two HashMaps.

Map<Integer, String> map1 = Map.of( 1, "Ned", 2, "Jon", 3, "Khal" ); Map<Integer, String> map2 = Map.of( 1, "Tywin", 2, "Jon", 4, "Petyr" );
Code language: Java (java)

Comparing the entries between the maps, first entry of the second map has a different value. Second entry has the same value, while the third entry is new.

Java Streams

In this section, we will use Java Streams API to combine two maps. As mentioned previously, we will also understand what is the duplicate key problem and a way to solve that.

Using Stream.of()

The Stream#of() method creates a stream of given elements. We’ll use it to create a stream of two maps and then use flatMap() to create a combined stream of their entry objects.

Map<Integer, String> map3 = Stream.of(map1, map2) .flatMap(map -> map.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue));
Code language: Java (java)

At first, we created a stream of two maps and used flatMap() to create a combined stream of their Entry elements. At the end we are using a Java Stream Collector toMap() method to collect the key and value pairs from the stream as a new Java Map.

However, given that our maps contains a same key with different values, the above merge operation will fail with an IllegalStateException.

Exception in thread "main" java.lang.IllegalStateException: 
Duplicate key 1 (attempted merging values Ned and Tywin)

To solve this duplicate key problem, we will have to provide a merge function which is of BinaryOperator type.

public static <T, K, U> Collector<T, ?, Map<K,U>> toMap( Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction)
Code language: JavaScript (javascript)

As shown the toMap() method definition, we can provide a merge function as third argument.

Solving the IllegalStateException caused by Duplicate Key Problem.

Map<Integer, String> map3 = Stream.of(map1, map2) .flatMap(map -> map.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (value1, value2) -> value1));
Code language: Java (java)

In the merge function, we chose the value from the first map and that resolves the exception.

{1=Ned, 2=Jon, 3=Khal, 4=Petyr}

Upon, printing the output map we can confirm the first element has value from map1.

Using Stream.concat()

Alternatively, we can use Stream#concat() function to merge the maps together. This function can combine two different streams into one.

Map<Integer, String> map3 = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1));
Code language: Java (java)

As shown in the snippet, we are passed the streams of map1 and map2 to the concate() function and then collected the stream of their combined entry elements. Similar to the previous example, we provided a merge function to specify our merging strategy.

Plain Java

Java without streams also offers a couple of ways to merge Java maps together. Let’s go over them quickly.

Using Map.putAll()

We can use putAll() method on any map instance and put all the entries from the given map into it.

Map<Integer, String> map3 = new HashMap<>(); map3.putAll(map1); map3.putAll(map2);
Code language: Java (java)

First, we created an empty output map and then added all the entries from both of the maps into it.

{1=Tywin, 2=Jon, 3=Khal, 4=Petyr}

As a result, we got merged entries from both of our maps. We can also see that the first entry of the result has value from the map2. Because putAll() method will replace any existing values if it finds duplicate keys.

If we want value from the first map to be chosen, we can add map2 before map1.

Using Map.merge()

The map#merge() function adds a given key value pair into the map. Here, is the JavaDoc definition of the merge function.

default V merge( K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
Code language: Java (java)

If the given key doesn’t exist or has a null value in the current map, the given value is used. If the given key already exists in the current map, it uses the merging strategy provided by the remapping function.

Map<Integer, String> map3 = new HashMap<>(map1); map2.forEach((key, value) -> map3.merge( key, value, (value1, value2) -> value1));
Code language: Java (java)

Firstly, we created our output map using all the entries from map1. Next, we iterated through each key and value pairs from the map2 and merged them into the map3. Note that, in the remapping function we are choosing the value1 which corresponds the original value from map1.

{1=Ned, 2=Jon, 3=Khal, 4=Petyr}

As expected, we can see the first entry has the value from map1.

Summary

In this quick tutorial we covered a different ways of merging two Map instances in Java. We used Java Stream API as well as plain Java methods to join two maps and create an output map of their elements merged together. Also, we understood the reasoning behind the IllegalStateException that we get while merging two maps with duplicate keys. We handled the duplicate key problem by providing a custom merging strategy.

For full source of the examples used here, please visit our Github Repository.