315

I have two HashMap objects defined like so:

HashMap<String, Integer> map1 = new HashMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();

I also have a third HashMap object:

HashMap<String, Integer> map3;

How can I merge map1 and map2 together into map3?

1
  • 2
    After seeing all the responses, and reading baeldung.com/java-merge-maps it seems like there is no clean way to do this with lambdas. Disappointing. Commented Aug 25, 2022 at 0:00

18 Answers 18

438
map3 = new HashMap<>();

map3.putAll(map1);
map3.putAll(map2);
Sign up to request clarification or add additional context in comments.

8 Comments

thank you, I am merging the Maps in a for loop which uses a method return a map and need to merge it to another map and apply the same method agian. For this, i get null pointer exception with putAll method. it does not help using try/catch block. what should i do? I am apply if condition, that if size==o then don't apply putAll else apply it and so on....
If you get a NPE, then apparently you did not initialize one of your objects properly. Do you print the stacktrace in the catch block? So you know where the problem arises. But unless you post the full and exact code including the stack trace you will need to track that down on your own.
Note that, with this solution, if a key exists in both maps, the value in map2 will be preserved and the value in map1 lost.
@MichaelScheper: what else do you expect? Keys in a Map are by definition unique
I don't know what the OPer expects. Maybe he expects the map1 values to have precedence, or an exception to be thrown, or for some 'merging' operation to be performed on intersecting Integers. Or maybe, since this is a beginner's question, this is a case the OPer hadn't considered, in which case my comment would hopefully be helpful.
|
131

If you know you don't have duplicate keys, or you want values in map2 to overwrite values from map1 for duplicate keys, you can just write

map3 = new HashMap<>(map1);
map3.putAll(map2);

If you need more control over how values are combined, you can use Map.merge, added in Java 8, which uses a user-provided BiFunction to merge values for duplicate keys. merge operates on individual keys and values, so you'll need to use a loop or Map.forEach. Here we concatenate strings for duplicate keys:

map3 = new HashMap<>(map1);
for (Map.Entry<String, String> e : map2.entrySet())
    map3.merge(e.getKey(), e.getValue(), String::concat);
//or instead of the above loop
map2.forEach((k, v) -> map3.merge(k, v, String::concat));

If you know you don't have duplicate keys and want to enforce it, you can use a merge function that throws an AssertionError:

map2.forEach((k, v) ->
    map3.merge(k, v, (v1, v2) ->
        {throw new AssertionError("duplicate values for key: "+k);}));

Taking a step back from this specific question, the Java 8 streams library provides toMap and groupingBy Collectors. If you're repeatedly merging maps in a loop, you may be able to restructure your computation to use streams, which can both clarify your code and enable easy parallelism using a parallel stream and concurrent collector.

Comments

89

One-liner using Java 8 Stream API:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue))

Among the benefits of this method is ability to pass a merge function, which will deal with values that have the same key, for example:

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))

5 Comments

this will throw IllegalStateException for duplicate keys
@ArpitJ. that's the whole point of the second variation. Sometimes you want the exception, sometimes you don't.
I wonder why this answer is so less upvoted.
I would have missed this answer completely after being disillusioned by the other answers. I only used Cmd + F to reach this far after reading stackoverflow.com/a/52310807/714112
The nicest, cleanest - the best solution.
44

Java 8 alternative one-liner for merging two maps:

defaultMap.forEach((k, v) -> destMap.putIfAbsent(k, v));

The same with method reference:

defaultMap.forEach(destMap::putIfAbsent);

Or idemponent for original maps solution with third map:

Map<String, Integer> map3 = new HashMap<String, Integer>(map2);
map1.forEach(map3::putIfAbsent);

And here is a way to merge two maps into fast immutable one with Guava that does least possible intermediate copy operations:

ImmutableMap.Builder<String, Integer> builder = ImmutableMap.<String, Integer>builder();
builder.putAll(map1);
map2.forEach((k, v) -> {if (!map1.containsKey(k)) builder.put(k, v);});
ImmutableMap<String, Integer> map3 = builder.build();

See also Merge two maps with Java 8 for cases when values present in both maps need to be combined with mapping function.

Comments

36

If you don't need mutability for your final map, there is Guava's ImmutableMap with its Builder and putAll method which, in contrast to Java's Map interface method, can be chained.

Example of use:

Map<String, Integer> mergeMyTwoMaps(Map<String, Integer> map1, Map<String, Integer> map2) {
  return ImmutableMap.<String, Integer>builder()
      .putAll(map1)
      .putAll(map2)
      .build();
}

Of course, this method can be more generic, use varargs and loop to putAll Maps from arguments etc. but I wanted to show a concept.

Also, ImmutableMap and its Builder have few limitations (or maybe features?):

  • they are null hostile (throw NullPointerException - if any key or value in map is null)
  • Builder don't accept duplicate keys (throws IllegalArgumentException if duplicate keys were added).

Comments

31

HashMap has a putAll method.

http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html

1 Comment

What is the runtime for this command? doc doesn't seem to specify. I would assume Theta(N)?
24

You could use Collection.addAll() for other types, e.g. List, Set, etc. For Map, you can use putAll.

Comments

13

Generic solution for combining two maps which can possibly share common keys:

In-place:

public static <K, V> void mergeInPlace(Map<K, V> map1, Map<K, V> map2,
        BinaryOperator<V> combiner) {
    map2.forEach((k, v) -> map1.merge(k, v, combiner::apply));
}

Returning a new map:

public static <K, V> Map<K, V> merge(Map<K, V> map1, Map<K, V> map2,
        BinaryOperator<V> combiner) {
    Map<K, V> map3 = new HashMap<>(map1);
    map2.forEach((k, v) -> map3.merge(k, v, combiner::apply));
    return map3;
}

Comments

7

Very late but let me share what I did when I had the same issue.

Map<String, List<String>> map1 = new HashMap<>();
map1.put("India", Arrays.asList("Virat", "Mahi", "Rohit"));
map1.put("NZ", Arrays.asList("P1","P2","P3"));

Map<String, List<String>> map2 = new HashMap<>();
map2.put("India", Arrays.asList("Virat", "Mahi", "Rohit"));
map2.put("NZ", Arrays.asList("P1","P2","P4"));

Map<String, List<String>> collect4 = Stream.of(map1, map2)
                .flatMap(map -> map.entrySet().stream())
                .collect(
                        Collectors.toMap(
                                Map.Entry::getKey,
                                Map.Entry::getValue,
                                (strings, strings2) -> {
                                    List<String> newList = new ArrayList<>();
                                    newList.addAll(strings);
                                    newList.addAll(strings2);
                                    return newList;
                                }
                        )
                );
collect4.forEach((s, strings) -> System.out.println(s+"->"+strings));

It gives the following output

NZ->[P1, P2, P3, P1, P2, P4]
India->[Virat, Mahi, Rohit, Virat, Mahi, Rohit]

Comments

4

A small snippet I use very often to create map from other maps:

static public <K, V> Map<K, V> merge(Map<K, V>... args) {
    final Map<K, V> buffer = new HashMap<>();

    for (Map m : args) {
        buffer.putAll(m);
    }

    return buffer;
}

Comments

3

you can use HashMap<String, List<Integer>> to merge both hashmaps and avoid losing elements paired with the same key.

HashMap<String, Integer> map1 = new HashMap<>();
HashMap<String, Integer> map2 = new HashMap<>();
map1.put("key1", 1);
map1.put("key2", 2);
map1.put("key3", 3);
map2.put("key1", 4);
map2.put("key2", 5);
map2.put("key3", 6);
HashMap<String, List<Integer>> map3 = new HashMap<>();
map1.forEach((str, num) -> map3.put(str, new ArrayList<>(Arrays.asList(num))));
//checking for each key if its already in the map, and if so, you just add the integer to the list paired with this key
for (Map.Entry<String, Integer> entry : map2.entrySet()) {
    Integer value = entry.getValue();
    String key = entry.getKey();
    if (map3.containsKey(key)) {
        map3.get(key).add(value);
    } else {
        map3.put(key, new ArrayList<>(Arrays.asList(value)));
    }
}
map3.forEach((str, list) -> System.out.println("{" + str + ": " + list + "}"));

output:

{key1: [1, 4]}
{key2: [2, 5]}
{key3: [3, 6]}

Comments

3

You can use putAll function for Map as explained in the code below

HashMap<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("a", 1);
map1.put("b", 2);
map1.put("c", 3);
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
map1.put("aa", 11);
map1.put("bb", 12);
HashMap<String, Integer> map3 = new HashMap<String, Integer>();
map3.putAll(map1);
map3.putAll(map2);
map3.keySet().stream().forEach(System.out::println);
map3.values().stream().forEach(System.out::println);

Comments

2

Assuming the following input:

    import java.util.stream.Stream;
    import java.util.stream.Collectors;
    import java.util.Map;
   
    ...

    var m1 = Map.of("k1", 1, "k2", 2);
    var m2 = Map.of("k3", 3, "k4", 4);

When you're sure not to have any key collisions between both input maps, a simple expression that avoids any mutations and yields an immutable result could be:

    var merged = Stream.concat(
        m1.entrySet().stream(),
        m2.entrySet().stream()
    ).collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));

In case key collisions are possible, we can provide a lambda to specify how to de-duplicate them. For example if we'd like to keep the largest value in case an entry is present in both input, we could:

    .collect(Collectors.toUnmodifiableMap(
        Map.Entry::getKey,
        Map.Entry::getValue,
        Math::max))  // any function  (Integer, Integer) -> Integer  is ok here

Comments

1
    HashMap<Integer,String> hs1 = new HashMap<>();
    hs1.put(1,"ram");
    hs1.put(2,"sita");
    hs1.put(3,"laxman");
    hs1.put(4,"hanuman");
    hs1.put(5,"geeta");

    HashMap<Integer,String> hs2 = new HashMap<>();
    hs2.put(5,"rat");
    hs2.put(6,"lion");
    hs2.put(7,"tiger");
    hs2.put(8,"fish");
    hs2.put(9,"hen");

    HashMap<Integer,String> hs3 = new HashMap<>();//Map is which we add

    hs3.putAll(hs1);
    hs3.putAll(hs2);

    System.out.println(" hs1 : " + hs1);
    System.out.println(" hs2 : " + hs2);
    System.out.println(" hs3 : " + hs3);

Duplicate items will not be added(that is duplicate keys) as when we will print hs3 we will get only one value for key 5 which will be last value added and it will be rat. **[Set has a property of not allowing the duplicate key but values can be duplicate]

Comments

0

Method 1: Put maps in a List and then join

public class Test15 {
public static void main(String[] args) {

    Map<String, List<String>> map1 = new HashMap<>();
    map1.put("London", Arrays.asList("A", "B", "C"));
    map1.put("Wales", Arrays.asList("P1", "P2", "P3"));

    Map<String, List<String>> map2 = new HashMap<>();
    map2.put("Calcutta", Arrays.asList("Protijayi", "Gina", "Gini"));
    map2.put("London", Arrays.asList( "P4", "P5", "P6"));
    map2.put("Wales", Arrays.asList( "P111", "P5555", "P677666"));
    
    System.out.println(map1);System.out.println(map2);
    
    
    
    // put the maps in an ArrayList
    
    List<Map<String, List<String>>> maplist = new ArrayList<Map<String,List<String>>>();
    maplist.add(map1);
    maplist.add(map2);
    /*
<T,K,U> Collector<T,?,Map<K,U>> toMap(

                                  Function<? super T,? extends K> keyMapper,

                                  Function<? super T,? extends U> valueMapper,

                                  BinaryOperator<U> mergeFunction)
    */
    
 Map<String, List<String>> collect = maplist.stream()
    .flatMap(ch -> ch.entrySet().stream())
    .collect(
            Collectors.toMap(
            
            //keyMapper,
            
            Entry::getKey,
            
            //valueMapper
            Entry::getValue,
            
            // mergeFunction
     (list_a,list_b) -> Stream.concat(list_a.stream(), list_b.stream()).collect(Collectors.toList())
            
            ));
    
    
    
    System.out.println("Final Result(Map after join) => " + collect);
    /*
    {Wales=[P1, P2, P3], London=[A, B, C]}
{Calcutta=[Protijayi, Gina, Gini], Wales=[P111, P5555, P677666], London=[P4, P5, P6]}
Final Result(Map after join) => {Calcutta=[Protijayi, Gina, Gini], Wales=[P1, P2, P3, P111, P5555, P677666], London=[A, B, C, P4, P5, P6]}
*/
    
}//main


}

Method 2 : Normal Map merge

public class Test15 {
public static void main(String[] args) {

    Map<String, List<String>> map1 = new HashMap<>();
    map1.put("London", Arrays.asList("A", "B", "C"));
    map1.put("Wales", Arrays.asList("P1", "P2", "P3"));

    Map<String, List<String>> map2 = new HashMap<>();
    map2.put("Calcutta", Arrays.asList("Protijayi", "Gina", "Gini"));
    map2.put("London", Arrays.asList( "P4", "P5", "P6"));
    map2.put("Wales", Arrays.asList( "P111", "P5555", "P677666"));
    
    System.out.println(map1);System.out.println(map2);
    
    
    

    /*
<T,K,U> Collector<T,?,Map<K,U>> toMap(

                                  Function<? super T,? extends K> keyMapper,

                                  Function<? super T,? extends U> valueMapper,

                                  BinaryOperator<U> mergeFunction)
    */
    
    
Map<String, List<String>> collect = Stream.of(map1,map2)
    .flatMap(ch -> ch.entrySet().stream())
    .collect(
            Collectors.toMap(
            
            //keyMapper,
            
            Entry::getKey,
            
            //valueMapper
            Entry::getValue,
            
            // mergeFunction
     (list_a,list_b) -> Stream.concat(list_a.stream(), list_b.stream()).collect(Collectors.toList())
            
            ));
    
    
    
    System.out.println("Final Result(Map after join) => " + collect);
    /*
    {Wales=[P1, P2, P3], London=[A, B, C]}
{Calcutta=[Protijayi, Gina, Gini], Wales=[P111, P5555, P677666], London=[P4, P5, P6]}
Final Result(Map after join) => {Calcutta=[Protijayi, Gina, Gini], Wales=[P1, P2, P3, P111, P5555, P677666], London=[A, B, C, P4, P5, P6]}

*/
    
}//main


}
    

In Python, HashMap is called Dictionary and we can merge them very easily.

x = {'Roopa': 1, 'Tabu': 2}
y = {'Roopi': 3, 'Soudipta': 4}


z = {**x,**y}
print(z)
{'Roopa': 1, 'Tabu': 2, 'Roopi': 3, 'Soudipta': 4}

Comments

0
new HashMap(Map.of("k1", 1) 
{{   putAll(Map.of("k2", 2)}}
//Options 2: if you don't wanna use an Anonymous inner class, you can:
Map m;
(m = new HashMap(Map.of("k1", 1)))
         .putAll(Map.of("k2", 2)); 

This is the shortest way to concat two Maps into a new Map, as far as I'm aware. For brevities sake, I use Map.of a lot for small Map sizes. Polymorphically, Map.of provides methods accepting between 0 & at most 10 key/value pairs, and when that's not enough, I usually write something like this to concat two Map.of Maps.

Oracle docs for creating immutable Lists, Sets, and Maps

Comments

0

I use this to initialize in a single line,

final Map<String, Object> map = new HashMap<>() {{
    putAll(map1);
    putAll(map2);
}};

CAUTION: DO NOT USE ABOVE ONE! After reading below comment from @Ian Robertson, I quit using this.

2 Comments

Note that this is often considered an anti-pattern in Java, as under the covers it creates a new subclass of HashMap, adding to Metaspace usage, and in some cases can lead to memory leaks.
Thank you for heads up! I updated my answer accordingly
-1

you can use - addAll method

http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html

But there is always this issue that - if your two hash maps have any key same - then it will override the value of the key from first hash map with the value of the key from second hash map.

For being on safer side - change the key values - you can use prefix or suffix on the keys - ( different prefix/suffix for first hash map and different prefix/suffix for second hash map )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.