Hello guys, in this blog, we are going to talk about the new methods which were introduced in Java 8. Following are the ones which we will look into in detail.
Initially, we will look into the basic examples of each one of them, and later on, we will see how it works in the case of a multi-threaded environment.
Let us start with computeIfAbsent method.
The computeIfAbsent method takes a key and mapping function as an input. If the specified key is not present in the map or it is mapped to a null value, then the mapping function is executed. If the mapping function returns null or throws an exception, no mapping is recorded.
In the above example, the key “abc” does not exist and therefore, the mapping function is executed and the result of it is assigned to that key. Here, the return type of computeIfAbsent method is Integer as we have specified as a type parameter in the map. In the second case, the mapping function is executed since the value of the key “xyz” is null. In the third case, a new entry is not added to the map because the mapping function returns null.
If the value type of the map is a collection, then you can use it to store multiple values. Here is an example of the same.
Now, the next method is computeIfPresent.
The computeIfPresent method is the opposite of the computeIfAbsent method. This method takes a key and a BiFunction mapping. The input to this mapping function is the key that we have provided and the corresponding value which is present in the map. The mapping function is executed only if the key exists and the corresponding value is non-null. If the mapping function yields a null value, the key-value pair is removed from the map and if the mapping function throws an exception, the key-value pair remains unchanged in the map.
Let us move on to the next one which is the compute method.
You can think of the compute method as a combination of computeIfAbsent and computeIfPresent methods. The compute method takes a key and a BiFunction mapping. Again the input to this mapping function is a key and its corresponding value. If the value is null then the mapping function can be used to create a new value otherwise, it can be used to update/replace an existing value. If the mapping function returns null, then the existing key-value pair is removed. If the mapping function throws an exception, the key-value pair remains unchanged.
The next one is the merge method.
As the name suggests, the merge method is used to merge something into the map. The merge method takes three inputs, the first one is the key, the second one is the value. This value is used when the key does not exist in the map or the value of that key is null. The third one is the mapping function which is executed only if the key exists in the map. The result of this mapping function is used to update/replace the existing value. If the result of the mapping function is null, the key-value pair is removed from the map.
The next part of this blog is about the difference between the hashmap and the concurrent hashmap in Java 8.
As we all know that hashmap is not thread-safe. So even the implementations of the newly introduced methods are also not thread safe and they are not atomic. See the example below.
In the above program, I have two worker threads. Each thread is calling computeIfAbsent on the map using the key “pqr”. As we have learned, the computeIfAbsent gets executed only when the key is not present in the map or the value of the key is null. In an ideal scenario, you would want only one thread must be able to execute computeIfAbsent method. But in this case, the computeIfAbsent is executed by both the threads which can lead to inconsistent results. This is happening due to context switching and not having exclusive access to the computeIfAbsent method.
Now let us try the same example with a concurrent hashmap.
Now if you see the output, you will always get only one of the threads executing the computeIfAbsent method. This is because some kind of locking is involved when this function is invoked. Such locking is very fine-grained and only involves a small portion of the implementation. Thus, the methods — computeIfAbsent, computeIfPresent, compute and merge of concurrent hashmap are atomic methods and can be used in a multithreaded environment without any explicit locking.
I hope you guys understood the key difference between the hashmap and the concurrent hashmap in Java 8.
That's it from this blog. I hope you guys liked it. Do send your comments and suggestions.