Map Methods in Java
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
| Method | Description |
|---|---|
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.
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"));
}
}Pune
unknown
Pune, DelhiExplanation: 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:
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);
}
}{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
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);
}
}{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:
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) + ")");
}
}{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
- Easy: Count how many times each character appears in "Anamaneni" using
merge. - Harder: Given a list of (student, subject, mark) records, build a
Map<String, Map<String, Integer>>from student to subject to mark usingcomputeIfAbsent, then print each student's total.
Key Takeaways
Was this tutorial helpful?