Back to Stream: map & Transform
Q19Question 19 of 34

Merge two Map<String, Integer> maps, summing values for duplicate keys

Key Concepts
  • Map.merge(key, value, Integer::sum) inserts if absent, sums if the key already exists
  • The stream approach concatenates both entrySets and collects with toMap using Integer::sum as the merge function
  • Both approaches produce identical results; choose based on context (loop vs functional style)
  • The merge function decides the combination strategy: sum, max, latest, or custom
  • Map.merge removes the key if the remapping function returns null (a subtle but documented behaviour)
  • For immutable source maps, the stream approach avoids mutation

Definition

Map.merge(key, value, Integer::sum) adds values on key clashes when combining two maps.
  • Map.merge(key, value, remappingFunction) inserts the value if the key is absent, otherwise applies the function to the existing and new values.
  • Integer::sum sums the two values on a key clash.
  • The stream approach concatenates both entrySets and collects with toMap(key, value, Integer::sum).
  • If the remapping function returns null, the key is removed from the map.

Two branches at the National Bank of India each send Priya a tally of transactions per product. She combines them into one tally, and where both branches report the same product she adds the two counts together.

Understanding the Concepts

How do you merge two maps with Map.merge?

Copy the first map, then for each entry of the second, call merge with Integer::sum.

JAVA
package com.bank.ops;

import java.util.*;

public class MergeMaps {
    public static void main(String[] args) {
        Map<String, Integer> branch1 = Map.of(
            "Savings", 120, "Current", 80, "Loan", 45);
        Map<String, Integer> branch2 = Map.of(
            "Savings", 95, "FD", 60, "Loan", 30);

        Map<String, Integer> combined = new HashMap<>(branch1);
        branch2.forEach((key, value) ->
            combined.merge(key, value, Integer::sum));

        System.out.println(combined);
    }
}
TEXT
{Savings=215, Current=80, Loan=75, FD=60}

How do you merge using streams?

Concatenate both entrySets into one stream and collect with toMap.

JAVA
import java.util.stream.*;

Map<String, Integer> merged = Stream.concat(
        branch1.entrySet().stream(),
        branch2.entrySet().stream())
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        Map.Entry::getValue,
        Integer::sum));

System.out.println(merged);
TEXT
{Savings=215, Current=80, Loan=75, FD=60}

How does Map.merge work internally?

| Key present? | Behaviour |
|---|---|
| No | Inserts the new value |
| Yes | Applies remappingFunction(existingValue, newValue) and stores the result |
| Yes, and function returns null | Removes the key |

JAVA
Map<String, Integer> m = new HashMap<>(Map.of("A", 10));
m.merge("A", 5, Integer::sum);   // A = 15 (10 + 5)
m.merge("B", 7, Integer::sum);   // B = 7  (inserted)
m.merge("A", 0, (a, b) -> null); // A removed!
System.out.println(m); // {B=7}

What merge strategies are common?

DIAGRAM
| Strategy | Merge function | Result for (10, 5) |
|---|---|---|
| Sum | Integer::sum | 15 |
| Max | Integer::max | 10 |
| Keep first | (a, b) -> a | 10 |
| Keep latest | (a, b) -> b | 5 |
| Concatenate (strings) | String::concat | "firstsecond" |

What are common mistakes?

Mistake: mutating an unmodifiable map.

JAVA
// WRONG: Map.of returns an unmodifiable map
Map<String, Integer> result = Map.of("A", 10);
result.merge("A", 5, Integer::sum);  // UnsupportedOperationException!

// CORRECT: copy into a mutable map first
Map<String, Integer> mutable = new HashMap<>(Map.of("A", 10));
mutable.merge("A", 5, Integer::sum);

What should a senior engineer know?

  • Map.merge also removes a key if the remapping function returns null, which is a subtle but documented behaviour.
  • For immutable inputs, the stream approach is cleaner because it does not mutate any source.
  • For accumulating in a loop, the merge method is idiomatic.
  • Both approaches handle the case where a key exists in only one map: it carries through unchanged.

What are common interview follow-up questions?

DIAGRAM
- "How do you merge more than two maps?" Stream.of(map1, map2, map3).flatMap(m -> m.entrySet().stream()).collect(toMap(k, v, merge)).
- "How do you merge maps of lists?" Use (a, b) -> { a.addAll(b); return a; } or Stream.concat lists.
- "What if the maps have different value types?" You cannot use merge directly; convert to a common type first.

Visual Overview

DIAGRAM
  Branch 1: {Savings=120, Current=80, Loan=45}
  Branch 2: {Savings=95,  FD=60,     Loan=30}
       │
       │  merge each entry of Branch 2 into copy of Branch 1
       ▼
  Savings: 120 + 95 = 215   (sum)
  Current: 80               (only in branch1)
  Loan:    45 + 30 = 75     (sum)
  FD:      60               (only in branch2)
       │
       ▼
  Combined: {Savings=215, Current=80, Loan=75, FD=60}

Key Takeaway

Two clean ways to merge maps with summing on duplicate keys: the imperative way copies the first map and calls merge with Integer::sum for each entry of the second. The functional way concatenates both entrySets into one stream and collects with toMap using Integer::sum as the merge function.

Both produce identical results. At the National Bank of India, this consolidated daily transaction tallies from two branches. Choose the stream form for immutable inputs and the merge-loop form when building up an accumulator.

Be deliberate about merge semantics: sum for counts, max for versions, keep-latest for updates. And know the subtle behaviour: if the remapping function returns null, the key is removed from the map.

Remember one sentence: Map.merge inserts if absent and applies the remapping function if present, and Integer::sum combines counts for duplicate keys.

---

Share
Use ← → arrow keys to navigate