In this article, we look at the ins and outs of Java HashMap computeIfAbsent() from Java 8.
Overview
The computeIfAbsent method is introduced to the HashMap data structure from Java 8 version.
The syntax of this method is as follows
public V computeIfAbsent(K key, Function mappingFunction)
- Here key represents the key in the Hash map.
- mappingFunction is a function that computes the value. Remember that the mapping function is only called when the value mapped to the key does not exist or it is null.
How does computeIfAbsent() work?
- If the given key is not already mapped to a value (or is mapped to null), the mappingFunction is invoked to compute the value and enters into the map if it is not null.
- If the mappingFunction returns null, the map will not be updated.
- If the mappingFunction throws a runtime exception, the exception is rethrown, and this map will not be updated for the provided key.
- The mappingFunction should not modify this map during computation.
- Throws ConcurrentModifiedException if it is detected that the mapping function modified this map.
When should we use computeIfAbsent()?
- Most common usage is to insert a key/value pair into the hashmap where the value is always a new object
initially.
ex: instead of
Map<String, Foo> fooMap = new HashMap<>();
if(fooMap.get("foo") == null) {
fooMap.put("foo", new Foo());
} else {
// update foo
}
we can use computeIfAbsent() as below and avoid the if/else checks.
Map<String, Foo> fooMap = new
HashMap<>();fooMap.computeIfAbsent("foo", k -> new Foo());
// update foo
- To implement a multi-value map, Map<K, Collection<V>> i.e having multiple values per key.
ex: Instead of
Map<String, List<Foo>> fooListMap = new HashMap<>();
if(fooListMap.get("foo") == null) {
fooListMap.put("foo", new ArrayList<Foo>());
}
fooListMap.get("foo").add(new Foo());
we can use computeIfAbsent() as below and write in a single statement.
Map<String, List<Foo>> fooListMap = new HashMap<>();
fooListMap.computeIfAbsent("foo", k -> new ArrayList<Foo>()).add(new Foo());
Further examples
Using computeIfAbsent() when the value is null
When the key is not mapped to a value or the mapped value is null, then the computeIfAbsent() method invokes the mapping function to derive the value. Remember, if the mapping function returns a null, then the map will not be updated.
Map stringMap = new HashMap<>();
System.out.println(stringMap.get("TheBackendPro")); // prints null
stringMap.computeIfAbsent("TheBackendPro", k -> {
return "https://www.thebackendpro.com/";
});
System.out.println(stringMap.get("TheBackendPro")); // prints https://www.thebackendpro.com/
Using computeIfAbsent() when the key is already mapped to a non-null value
If the key is already associated with a non-null value, the computeIfAbsent() doesn't invoke the mapping function as the value is already present.
Map stringMap = new HashMap<>();
stringMap.put("TheBackendPro", "https://www.thebackendpro.com/");
stringMap.computeIfAbsent("TheBackendPro", k -> {
return "https://www.google.com/";
});
System.out.println(stringMap.get("TheBackendPro")); // prints https://www.thebackendpro.com/
Mapping Function Throws a Runtime Exception
When the mapping function throws a runtime exception, the same is propagated to the caller and no mapping is recorded for the key.
Map stringMap = new HashMap<>();
stringMap.computeIfAbsent("TheBackendPro", k -> {
throw new RuntimeException("unexpected exception occurred");
});
Output
Exception in thread "main" java.lang.RuntimeException: unexpected exception occurred
at main.java.ComputeIfAbsentTest.lambda$main$2(ComputeIfAbsentTest.java:26)
at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1134)
at main.java.ComputeIfAbsentTest.main(ComputeIfAbsentTest.java:25)