Map.merge and the compute family

Collections · lesson 22 of 42 · 4 min read

Update an entry from whatever is already there, in one call, with no null checks.

Open this lesson in the learning hub

Key points

  • merge(k, v, fn): a missing key stores v, an existing key stores fn(old, v). The counter idiom.
  • compute(k, fn) always runs the function, passing null for a missing key, and stores what it returns.
  • computeIfAbsent builds the value only when the key is missing — the standard way to fill a map of lists.
  • computeIfPresent never creates an entry, so it is the safe "update only if it exists" call.
  • Return null from any of these functions and the entry is removed. That is often exactly what you want.
  • On a ConcurrentHashMap all four are atomic per key, so no external lock is needed.

Example

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> votes = new LinkedHashMap<>();
        for (String v : List.of("java", "go", "java", "rust", "java")) {
            votes.merge(v, 1, Integer::sum);
        }
        System.out.println("merge as counter  : " + votes);

        votes.compute("go", (k, old) -> old == null ? 1 : old * 100);
        votes.compute("perl", (k, old) -> old == null ? 1 : old * 100);
        System.out.println("compute           : " + votes + "   (perl created)");

        votes.computeIfAbsent("zig", k -> 0);
        votes.computeIfPresent("rust", (k, old) -> old + 9);
        votes.computeIfPresent("cobol", (k, old) -> old + 9);
        System.out.println("ifAbsent/ifPresent: " + votes + "   (cobol never created)");

        votes.merge("zig", 0, (oldV, newV) -> null);
        System.out.println("remap returns null: " + votes + "   (zig removed)");

        System.out.println("getOrDefault      : " + votes.getOrDefault("ada", 0) + "   (map untouched)");
        votes.putIfAbsent("ada", 1);
        votes.putIfAbsent("java", 999);
        System.out.println("putIfAbsent       : " + votes + "   (java kept its 3)");
    }
}

merge for counters, computeIfAbsent for containers, and a null return to delete.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Collections course, and every lesson in it is listed on the Collections contents page.