Back to Blog
Java

Using HashMap getOrDefault in Java

Learn how to use HashMap.getOrDefault in Java to return a fallback value for missing keys, handle null values correctly, and avoid verbose null checks.

HashMapJava MapgetOrDefaultJava CollectionsNull Handling
Illustration of a HashMap with a key lookup returning a default value when the key is missing

When you look up a key in a HashMap with get, you get null if the key is absent. That typically forces you to write a null check before using the result. The getOrDefault method, added to the Map interface in Java 8, eliminates that boilerplate by letting you specify a default value that is returned when the key is not present. It is a small addition, but it makes missing-key handling more natural.

Understanding the getOrDefault Method

The signature is straightforward:

V getOrDefault(Object key, V defaultValue)

If the map contains a mapping for the key, the mapped value is returned. Otherwise, defaultValue is returned. The method does not add the default value to the map; it only returns it. This is a read-only operation, so the map's size and contents remain unchanged.

Consider a simple example:

Map<String, Integer> scores = new HashMap<>(); scores.put("Alice", 90); int aliceScore = scores.getOrDefault("Alice", 0); // 90 int bobScore = scores.getOrDefault("Bob", 0); // 0

The second call returns 0 because "Bob" is not a key. Without getOrDefault, you would write:

Integer raw = scores.get("Bob"); int bobScore = raw == null ? 0 : raw;

The method is especially useful when you need a primitive value and want to avoid unboxing a null Integer.

How getOrDefault Differs from get

The get method returns null when the key is missing, but it also returns null when the key is present and explicitly mapped to null. getOrDefault does not remove that ambiguity: if the key exists with a null value, it returns the null value, not the default.

Map<String, String> map = new HashMap<>(); map.put("key", null); String value = map.getOrDefault("key", "fallback"); // returns null

This behavior is consistent with the Map contract, but it means you cannot use getOrDefault to treat an existing null value as if the key were missing. If you need to know whether the key exists even when its value might be null, use containsKey. If you want to replace a null value with a computed value, computeIfAbsent can do that, but it updates the map.

Practical Example: Counting Word Frequencies

A common use case is building a frequency counter. The naive approach requires a null check or a conditional put. With getOrDefault, the code becomes compact:

Map<String, Integer> frequencies = new HashMap<>(); for (String word : words) { frequencies.put(word, frequencies.getOrDefault(word, 0) + 1); }

Each time you encounter a word, you retrieve its current count or 0 if it is new, then increment and store. This pattern is idiomatic and avoids a containsKey check.

A more concise alternative for this specific case is merge, which combines the read and write in one call. getOrDefault is still readable and is a good choice when you only need to read a value with a fallback.

Handling Null Values with getOrDefault

getOrDefault only supplies a default when the key has no mapping. If the key is present with a null value, the method returns null. It is therefore not a null-safe getter:

Map<String, String> map = new HashMap<>(); map.put("key", null); String value = map.getOrDefault("key", "fallback"); // null

If you want to treat an explicit null value the same as a missing key, check the result and fall back explicitly:

String value = map.get("key"); if (value == null) { value = "fallback"; }

This treats both a missing key and a key mapped to null as “not found.”

If you need to distinguish between a missing key and a key mapped to null, use containsKey:

if (map.containsKey("key")) { // key exists, but its value may be null } else { // key does not exist }

If you want to replace a null value with a computed value and update the map, note that HashMap.computeIfAbsent treats a missing key and a key mapped to null as absent:

map.computeIfAbsent("key", k -> "computed fallback");

Performance Considerations

The performance impact of getOrDefault is negligible. The lookup cost is the same as get for a HashMap, and the method returns either the found value or the default. The main subtlety is that the default value expression is evaluated eagerly, even if the key is present, because Java evaluates method arguments before calling the method. If the default is a method call with side effects, those side effects occur on every invocation.

// This calls expensiveDefault() even when the key exists String value = map.getOrDefault("key", expensiveDefault());

If the default computation is costly or has side effects, consider computeIfAbsent, which computes the value only when there is no non-null mapping for the key. For most cases, however, the eager evaluation is irrelevant because the default is a constant or a simple literal.

When Not to Use getOrDefault

getOrDefault is not the right tool when you need to distinguish between a missing key and a key with a null value. In that case, use containsKey. It is also not ideal when the default value must be computed lazily to avoid unnecessary work; computeIfAbsent can be a better fit when you want to store the computed value in the map.

Another case is when you need to modify the map based on the current value, such as incrementing a counter. While getOrDefault works, merge is more concise and combines the lookup and update in one call:

map.merge(word, 1, Integer::sum);

The merge method handles the absent-key case by inserting the initial value, and the present-key case by applying the remapping function. This is often clearer than the getOrDefault pattern.

Common Pitfalls and Misconceptions

One misconception is that getOrDefault adds the default value to the map. It does not; the map remains unchanged. Another is that the default value is evaluated lazily. As mentioned, it is evaluated eagerly, so avoid placing expensive or side-effecting expressions in the default argument.

Also, remember that getOrDefault works with any Map implementation, not just HashMap. The behavior is defined in the Map interface, so TreeMap, LinkedHashMap, and other implementations follow the same contract. The only difference is the underlying data structure, which affects iteration order and performance characteristics.

Finally, be aware that the default value must be of the correct type. If the map is typed with a generic parameter, the default must match that type. Using a different type causes a compile-time error, which is good because it catches mistakes early.

HashMap getOrDefault in Java: Practical Usage and Code Examples | RYUSLOG DEV