Definition
- 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.
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);
}
}
{Savings=215, Current=80, Loan=75, FD=60}
How do you merge using streams?
Concatenate both entrySets into one stream and collect with toMap.
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);
{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 |
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?
| 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.
// 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?
- "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
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.
---