Map Methods in Java

Naveen AnamaneniUpdated · 6 min read

Since Java 8, the Map interface has a set of default methods that make common tasks short and safe: reading with a default, adding only when absent, updating a value based on its old value, and combining values. They replace the old pattern of "check with containsKey, then get, then put". In this lesson, you will learn each of these methods with an example, and build a word-frequency counter with merge.

The Methods

MethodDescription
getOrDefault(key, def)It returns the value for the key, or def if the key is absent.
putIfAbsent(key, value)It adds the pair only if the key is absent (or maps to null).
computeIfAbsent(key, k -> v)It computes and stores a value only if the key is absent, and returns the current value.
computeIfPresent(key, (k, v) -> v2)It replaces the value only if the key is present; returning null removes the entry.
compute(key, (k, v) -> v2)It computes a new value whether or not the key is present (v is null if absent).
merge(key, value, (old, v) -> v2)It stores value if the key is absent, otherwise combines the old and new values.
replaceAll((k, v) -> v2)It replaces every value using a function.
remove(key, value)It removes the entry only if the key currently maps to that value.
replace(key, value)It replaces the value only if the key is present.

Example: getOrDefault and putIfAbsent

Let's see an example of the two simplest methods.

Defaults.java▶ Try it
import java.util.HashMap;
import java.util.Map;
 
public class Defaults {
    public static void main(String[] args) {
        Map<String, String> city = new HashMap<>();
        city.put("Navika", "Pune");
 
        System.out.println(city.getOrDefault("Navika", "unknown"));
        System.out.println(city.getOrDefault("Srihitha", "unknown"));
 
        city.putIfAbsent("Navika", "Delhi");
        city.putIfAbsent("Srihitha", "Delhi");
        System.out.println(city.get("Navika") + ", " + city.get("Srihitha"));
    }
}
Output
Pune
unknown
Pune, Delhi

Explanation: getOrDefault returns the stored city, or "unknown" when the name is missing. putIfAbsent didn't change Navika's existing city but did add Srihitha's.

Example: computeIfAbsent for Grouping

computeIfAbsent is the cleanest way to build a map of lists:

Grouping.java▶ Try it
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
 
public class Grouping {
    public static void main(String[] args) {
        String[][] students = {
            {"Navika", "Pune"}, {"Srihitha", "Delhi"},
            {"Advitha", "Pune"}, {"Anamaneni", "Delhi"}};
 
        Map<String, List<String>> byCity = new TreeMap<>();
        for (String[] s : students) {
            byCity.computeIfAbsent(s[1], k -> new ArrayList<>()).add(s[0]);
        }
        System.out.println(byCity);
    }
}
Output
{Delhi=[Srihitha, Anamaneni], Pune=[Navika, Advitha]}

Explanation: For a new city, computeIfAbsent creates an empty list, stores it, and returns it. For a city already in the map, it returns the existing list. Either way, .add(...) adds the name to the right list in one line.

Example: compute, computeIfPresent and replaceAll

Updates.java▶ Try it
import java.util.LinkedHashMap;
import java.util.Map;
 
public class Updates {
    public static void main(String[] args) {
        Map<String, Integer> marks = new LinkedHashMap<>();
        marks.put("Navika", 91);
        marks.put("Srihitha", 78);
 
        marks.compute("Navika", (k, v) -> v == null ? 1 : v + 2);
        marks.compute("Advitha", (k, v) -> v == null ? 1 : v + 2);
        System.out.println(marks);
 
        marks.computeIfPresent("Srihitha", (k, v) -> v + 10);
        marks.computeIfPresent("Advitha", (k, v) -> null);
        System.out.println(marks);
 
        marks.replaceAll((k, v) -> Math.min(v, 95));
        System.out.println(marks);
    }
}
Output
{Navika=93, Srihitha=78, Advitha=1}
{Navika=93, Srihitha=88}
{Navika=93, Srihitha=88}

Explanation: compute runs for both a present key (Navika, 91 + 2) and an absent one (Advitha, starting at 1). computeIfPresent adds 10 to Srihitha, and returning null for Advitha removes that entry. replaceAll caps every mark at 95; no mark was higher, so nothing changed.

The Checkpoint: A Word-Frequency Counter with merge

merge is perfect for counting. If the key is new, it stores the given value; if not, it combines the old and new values with the function:

WordCount.java▶ Try it
import java.util.Map;
import java.util.TreeMap;
 
public class WordCount {
    public static void main(String[] args) {
        String text = "the cat and the dog and the bird";
        Map<String, Integer> counts = new TreeMap<>();
        for (String word : text.split(" ")) {
            counts.merge(word, 1, Integer::sum);
        }
        System.out.println(counts);
 
        String top = null;
        for (Map.Entry<String, Integer> e : counts.entrySet()) {
            if (top == null || e.getValue() > counts.get(top)) {
                top = e.getKey();
            }
        }
        System.out.println("Most frequent: " + top
            + " (" + counts.get(top) + ")");
    }
}
Output
{and=2, bird=1, cat=1, dog=1, the=3}
Most frequent: the (3)

Explanation: For each word, merge(word, 1, Integer::sum) stores 1 the first time and adds 1 to the old count after that. Without merge, this would need an if with containsKey, get and put. A TreeMap keeps the words sorted for printing.

Common Mistakes

Using putIfAbsent(key, new ArrayList<>()) to build lists. It creates a new list every call, even when not needed; computeIfAbsent creates one only when required.

Changing the map inside a compute function. The function must not modify the same map.

Forgetting that returning null from compute, computeIfPresent or merge removes the entry.

Interview Corner

What is the difference between putIfAbsent and computeIfAbsent?

putIfAbsent(key, value) takes an already-created value and stores it only if the key is absent, returning the previous value (or null). computeIfAbsent(key, mappingFunction) calls the function only when the key is absent, stores the result, and returns the current value for the key, existing or new. computeIfAbsent avoids creating values unnecessarily and is ideal for building maps of collections.

How would you count word frequencies in Java?

Loop over the words and call map.merge(word, 1, Integer::sum) on a HashMap<String, Integer> (or a TreeMap for sorted output). merge inserts 1 for a new word and adds 1 to the existing count otherwise. With streams, Collectors.groupingBy(w -> w, Collectors.counting()) does the same.

Practice

  1. Easy: Count how many times each character appears in "Anamaneni" using merge.
  2. Harder: Given a list of (student, subject, mark) records, build a Map<String, Map<String, Integer>> from student to subject to mark using computeIfAbsent, then print each student's total.

Quick check: Map methods

4 questions
1What does getOrDefault return for a missing key?
2Which method adds 1 to a counter or starts it at 1?
3What happens when a compute function returns null?
4Which method is best for building a map of lists?

Key Takeaways

Was this tutorial helpful?

Lesson 285 of 482