The Map.computeIfAbsent() method computes the mapped value for a key using a mapping function if the specified key does not exist in the Map or is mapped to a null
value. It has been added as the default method in the Map interface in Java 8.
1. When to Use the computeIfAbsent() Method?
1.1. When Mapper Function is an Expensive Operation
The Map.computeIfAbsent() should be used when computing the value is a “costly operation”. For example, if a Map stores a number as key and its factorial as value then we can use the computeIfAbsent() as computing factorial is a memory-intensive operation.
Map<Integer, BigInteger> map = new HashMap<>();
map.computeIfAbsent(5, Main::factorial);
map.computeIfAbsent(6, Main::factorial);
//Inserting in another place
map.computeIfAbsent(6, Main::factorial); //Factorial is not calculated here
static BigInteger factorial(Integer num) {
System.out.println("Calculating the factorial of : " + num);
return BigIntegerMath.factorial(num);
}
The program outputs the print statements only two times. In the third time, as the key already exists in the Map, the mapper function is not invoked and the factorial is not calculated.
Calculating the factorial of : 5
Calculating the factorial of : 6
1.2. Creating Multi Map
Another common use of computeIfAbsent() is to create a multi-valued map. A multi-value map maps a single key with multiple values, generally in a List.
In the following example, the first invocation with “State1” will result in creating a new List, mapping it to the key and adding “City1” to it. On the second invocation, since the key “State1” is already present, a new List will not be created and “City2” would be added to the existing list.
Map<String, List<String>> multiMap = new HashMap<>();
multiMap.computeIfAbsent("State1", k -> new ArrayList<>()).add("City1");
multiMap.computeIfAbsent("State1", k -> new ArrayList<>()).add("City2");
System.out.println(multiMap); //{State1=[City1, City2]}
2. Map.computeIfAbsent() Syntax
The method syntax is:
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)
Parameters
The computeIfAbsent() takes two parameters:
- key: the key for the mapping to be stored.
- mappingFunction: non-null mapping function would only be invoked if the given key is not mapped to any value. It computes the new value for the specified key.
Return Value
The computeIfAbsent() returns the current value (either new or old) associated with the key after computation. It can return null if no value is associated with the key.
If mappingFunction results
null
, then the mapping for the specified key is removed.
3. How to Use Mapper Function?
Let us see a few examples to understand the method usage better.
3.1. Mapper Function should not be NULL
The mapping function has to be non-null else a NullPointerException is thrown. In the following code, we are passing null as the mapper function, so it will throw the NullPointerException.
Map<Integer, BigInteger> map = new HashMap<>();
map.computeIfAbsent(6, null);
3.2. Mapper Function is allowed to return NULL
There may be cases where the mapping function returns null values. In such a scenario, an entry is not created in the Map but the operation does not throw any exception.
Map<Integer, BigInteger> map = new HashMap<>();
map.computeIfAbsent(7, k -> null); //No entry is created in the map
assertNull( map.get(7) );
3.3. Mapper Function throwing an unchecked exception
In case the mapping function throws an unchecked exception, the exception is re-thrown and no entry is created in the map.
In the following code, an exception has been thrown from the mapper function when we try to add key 7. In the catch block, we are confirming that they entry was not created in the Map.
try {
map.computeIfAbsent(7, k-> {
throw new RuntimeException();
});
} catch (Exception e) {
assertNull( map.get(7) );
}
4. Difference with compute() and computeIfPresent()
Map interface has 3 compute methods.
compute()
computeIfPresent()
computeIfAbsent()
These functions look the same but they are not. The compute()
and computeIfPresent()
uses the BiFunction as remapper function. It takes the specified key and currently mapped value as method arguments and attempts to compute a new mapping.
The compute()
invokes the mapping function always, whereas computeIfPresent()
invokes the mapper function only when the value is present for the specified key, and it is non-null.
Map<Integer, BigInteger> map = new HashMap<>();
map.put(1, null);
map.computeIfPresent(1, (k, v) -> Main.factorial(k)); //factorial is not executed
map.compute(1, (k, v) -> Main.factorial(k)); //factorial is executed
5. Conclusion
In this article, we looked at the Java 8 Map.computeIfAbsent() method. We learned when to use this method and how to handle NULL values and exceptions. We also compared it with compute() and computeIfPresent() methods.
Happy Learning !!
Comments