computeIfAbsent() method signature
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
The Map (and HashMap) computeIfAbsent() method takes two parameters. The first parameter is the key. The second parameter is the mappingFunction. In this method the mapping function is only called if the mapping is not presented.
How the Map computeIfAbsent() method works
As we already know, the Map.computeIfAbsent() method is passed two parameters, the key and the function for calculating the value for this key mappingFunction. Here is the logical algorithm of the method:- The method first checks if the passed key is represented in our Map.
- If the key is represented in Map (and it’s not null), then the method does nothing.
- Else if the key doesn’t represent in Map (or it’s null) the method calculates the value using mappingFunction to the key.
- If the resulting value is not null, then write a key-value pair to map.
if (map.get(key) == null)
{
V newValue = mappingFunction.apply(key);
if (newValue != null) map.put(key, newValue);
}
computeIfAbsent() code example
So, if the value is not in the Map, then the method will perform the changes. Let's take a look at a simple example:
import java.util.HashMap;
import java.util.Map;
//map.computeIfAbsent example
public class ComputeIfAbsentExample {
public static void main(String[] args) {
Map<String, String> myMap = new HashMap<>();
myMap.computeIfAbsent("here is my key", key -> key + ", " + "and this is a new value");
System.out.println(myMap.get("here is my key"));
}
}
The output is:
import java.util.HashMap;
import java.util.Map;
public class ComputeIfAbsentExample2 {
public static void main(String[] args) {
Map<String, String> myMap = new HashMap<>();
myMap.put("here is my key", "and here is my value");
myMap.computeIfAbsent("here is my key", key -> key + ", " + "and this is a new value");
System.out.println(myMap.get("here is my key"));
}
}
Here is the output:
One more Map ComputeIfAbsent() example
If you are familiar with the concept of caching, the computeIfAbsent() method probably reminds you of something. Let's take a look at a more complex parsing example. Let's call the computeIfAbsent() method twice to make sure that in the first case the value changes, while in the second it doesn't.
import java.util.HashMap;
import java.util.Map;
public class ComputeIfAbsentExample {
private static Map<String, Long> numbersMap = new HashMap<>();
public static Long stringToLong(String str) {
return numbersMap.computeIfAbsent(str, key -> {
System.out.println("parsing: " + key);
return Long.parseLong(key);
});
}
public static void main(String[] args) {
// will print:
// > parsing: 10
// > parsing: 25
// > 10+25=35
System.out.println("10+25=" + (stringToLong("10") + stringToLong("25")));
// will print:
// > parsing: 20
// > 10+25=45
// only "20" will be parsed this time, since "25" was already parsed and placed into `numbersMap` map before
System.out.println("20+25=" + (stringToLong("20") + stringToLong("25")));
// will print:
// > 10+20=30
// no parsing will occur, since both "10" and "20" were already parsed and placed into `numbersMap` map before
System.out.println("10+20=" + (stringToLong("10") + stringToLong("20")));
}
}
Here is the output:
Exception Handling in computeIfAbsent
One critical aspect of using computeIfAbsent
is understanding how it handles exceptions. If the mapping function throws a runtime exception, the exception propagates back to the caller, and the entry for the specified key remains unchanged in the map.
Example: Exception Propagation
The following example demonstrates how exceptions thrown by the mapping function propagate back to the computeIfAbsent
method:
import java.util.HashMap;
public class ComputeIfAbsentExceptionExample {
public static void main(String[] args) {
HashMap map = new HashMap<>();
try {
map.computeIfAbsent("key1", key -> {
if (key.equals("key1")) {
throw new RuntimeException("Mapping function exception");
}
return 42;
});
} catch (RuntimeException e) {
System.out.println("Exception caught: " + e.getMessage());
}
System.out.println("Map after computeIfAbsent: " + map);
}
}
Output:
Exception caught: Mapping function exception Map after computeIfAbsent: {}
Handling Null Return Values from the Mapping Function
When the mapping function returns null
, computeIfAbsent
does not add an entry for the specified key. This behavior can lead to subtle bugs if not handled explicitly.
Example: Null Return Value
Consider the following example where the mapping function returns null
:
import java.util.HashMap;
public class ComputeIfAbsentNullExample {
public static void main(String[] args) {
HashMap map = new HashMap<>();
map.computeIfAbsent("key1", key -> null);
System.out.println("Map after computeIfAbsent: " + map);
}
}
Output:
Map after computeIfAbsent: {}
To avoid issues, ensure the mapping function never returns null
, or handle the scenario explicitly if null
is a valid result.
Behavior When Key Is Associated with a Non-Null Value
If the key is already associated with a non-null value, computeIfAbsent
does not invoke the mapping function, and the existing value remains unchanged. This behavior ensures efficiency by avoiding unnecessary computations.
Example: Non-Null Value
The following example demonstrates how computeIfAbsent
behaves when the key is associated with a non-null value:
import java.util.HashMap;
public class ComputeIfAbsentNonNullExample {
public static void main(String[] args) {
HashMap map = new HashMap<>();
map.put("key1", "existingValue");
map.computeIfAbsent("key1", key -> "newValue");
System.out.println("Map after computeIfAbsent: " + map);
}
}
Output:
Map after computeIfAbsent: {key1=existingValue}
GO TO FULL VERSION