BackendBench
Coffee

Unravel › Java concepts › Collections and streams

Java language

Map idioms: merge, compute, entrySet

A handful of Map methods replace the clumsy "check, get, put" dance: merge for counting, computeIfAbsent for grouping, getOrDefault for lookups with a default, and entrySet for looping over keys and values together.

Learn these first

At a glance

Mental model

A tally sheet with helper stamps: "add one to this name's row, creating the row first if there is none" is a single stamp instead of five steps.

What happens, in order
  1. 1Counting: counts.merge(word, 1, Integer::sum)Grouping: groups.computeIfAbsent(key, k -> new ArrayList<>()).add(item).
  2. 2Default: map.getOrDefault(k, 0)Insert only if missing: putIfAbsent(k, v). Update only if present: computeIfPresent(k, (key, old) -> old + 1).
  3. 3Looping: for (Map.Entry<String, Integer> e : map.entrySet()) gives key and value in one pass; keySet() plus get(key) does a second lookup per keymap.forEach((k, v) -> ...) is the lambda form.
  4. 4Map.of(k1, v1, k2, v2) builds a small immutable map; Map.entry(k, v) is an immutable pair
Remember
Watch out
if (!map.containsKey(k)) map.put(k, ...) (two lookups, and not atomic)Modifying the map inside the loop over its entriesLooking up get(k) inside a keySet loop
Example (highlighted lines explain it)
import java.util.*;public class Words {  static Map<String, Integer> count(List<String> words) {    Map<String, Integer> counts = new TreeMap<>();    for (String w : words) counts.merge(w, 1, Integer::sum);    return counts;  }  static Map<Integer, List<String>> byLength(List<String> words) {    Map<Integer, List<String>> groups = new HashMap<>();    for (String w : words) groups.computeIfAbsent(w.length(), k -> new ArrayList<>()).add(w);    for (Map.Entry<Integer, List<String>> e : groups.entrySet()) System.out.println(e.getKey() + " " + e.getValue());    return groups;  }}
  1. line 5 uses merge, the core of Map idioms: merge, compute, entrySet
  2. line 10 uses compute, the core of Map idioms: merge, compute, entrySet
  3. line 11 uses entrySet, the core of Map idioms: merge, compute, entrySet
Read the full explanation (about 1 min)

A handful of Map methods replace the clumsy "check, get, put" dance: merge for counting, computeIfAbsent for grouping, getOrDefault for lookups with a default, and entrySet for looping over keys and values together.

A mental model

A tally sheet with helper stamps: "add one to this name's row, creating the row first if there is none" is a single stamp instead of five steps.

How it works

Counting: counts.merge(word, 1, Integer::sum). Grouping: groups.computeIfAbsent(key, k -> new ArrayList<>()).add(item).

Default: map.getOrDefault(k, 0). Insert only if missing: putIfAbsent(k, v). Update only if present: computeIfPresent(k, (key, old) -> old + 1).

Looping: for (Map.Entry<String, Integer> e : map.entrySet()) gives key and value in one pass; keySet() plus get(key) does a second lookup per key. map.forEach((k, v) -> ...) is the lambda form.

Map.of(k1, v1, k2, v2) builds a small immutable map; Map.entry(k, v) is an immutable pair.

Going deeper

keySet(), values() and entrySet() are live views: removing from them removes from the map, and changing the map while iterating a view throws ConcurrentModificationException (unless you remove through the iterator).

In computeIfAbsent the function must not modify the same map; HashMap can throw ConcurrentModificationException and ConcurrentHashMap can deadlock.

merge removes the entry when the function returns null, which is useful but also a surprise.

Under the hood

HashMap.merge and compute* find the bucket once and update in place, so they are also faster than separate get and put calls. ConcurrentHashMap makes the same methods atomic.

Common mistakes

  • if (!map.containsKey(k)) map.put(k, ...) (two lookups, and not atomic).
  • Modifying the map inside the loop over its entries.
  • Looking up get(k) inside a keySet loop.

How Unravel recognises it

When you paste code, Unravel looks for these signs of map idioms: merge, compute, entryset. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Map idioms: merge, compute, entrySet?

A handful of Map methods replace the clumsy "check, get, put" dance: merge for counting, computeIfAbsent for grouping, getOrDefault for lookups with a default, and entrySet for looping over keys and values together.

What are the most common mistakes with Map idioms: merge, compute, entrySet?

if (!map.containsKey(k)) map.put(k, ...) (two lookups, and not atomic). Modifying the map inside the loop over its entries. Looking up get(k) inside a keySet loop.

How can I see Map idioms: merge, compute, entrySet in real code?

Paste your own Java into Unravel and it will point out where map idioms: merge, compute, entryset appears, explain how it works at the detail level you choose, and draw the flow of the code around it.