Java Map putIfAbsent vs computeIfAbsent
A frequently employed data structure, the Map stores key-value pairs. Java provides several methods for managing entries within a Map. With the introduction of Java 8, additional functionalities have been incorporated into the Map class. Let us delve into understanding Java Map putIfAbsent() and computeIfAbsent() methods.
1. Understanding putIfAbsent() Method in Java
The putIfAbsent()
method adds a key-value pair to a map only if the specified key is not already associated with a value, or is associated with a null
value. The method is represented by the following syntax:
V putIfAbsent(K key, V value)
Where:
K
: The type of keys maintained by this map.V
: The type of mapped values.key
: The key with which the specified value is to be associated.value
: The value to be associated with the specified key.
1.1 Key Points
- It is used to add a new key-value pair to the map.
- If the specified key already exists in the map, the method does not update its value.
- If the key does not exist or is associated with a
null
value, the specified value is added. - It returns the previous value associated with the key, or
null
if there was no mapping for the key.
1.2 Eager Evaluation with “put”
Contrastingly, the put()
method in Java maps follows an eager evaluation strategy. When using put()
, the value for the key is computed or added immediately, regardless of whether it will be used later or not. This means that even if the value is not needed immediately, it is still computed or added upfront.
While eager evaluation ensures that the value is available immediately when needed, it may result in unnecessary computation or resource utilization, especially if the value is not always needed.
2. Understanding computeIfAbsent() Method in Java
The computeIfAbsent()
method computes the value for a specified key if the key is not already associated with a non-null value in the map. The method is represented by the following syntax:
default V computeIfAbsent(K key, Function mappingFunction)
K
: The type of keys maintained by this map.V
: The type of mapped values.key
: The key whose value is to be computed.mappingFunction
: A function that computes the value for the key.
2.1 Key Points
- It is used to compute a value for a key if it is not already present in the map.
- If the specified key already exists in the map and is associated with a non-null value, the method does not compute a new value.
- The computation of the value is done using a provided mapping function.
- It returns the current (existing or computed) value associated with the key, or
null
if the mapping function produces anull
result.
2.2 Lazy Evaluation with “compute”
The computeIfAbsent()
method in Java maps follows a lazy evaluation strategy. This means that the computation of the value for a key is deferred until it is requested for the first time. If the key already exists in the map, and is associated with a non-null value, the computation is skipped entirely.
This lazy evaluation is particularly useful when dealing with computationally expensive operations or when the value for a key may not always be needed.
3. Code Example
Below is code example demonstrating the computeIfAbsent()
and putIfAbsent()
methods in Java:
package com.jcg.example; import java.util.HashMap; import java.util.Map; public class MapExamples { public static void main(String[] args) { // Example demonstrating putIfAbsent() method Map<String, Integer> map1 = new HashMap<>(); map1.put("key1", 1); map1.putIfAbsent("key2", 2); // key2 does not exist, so it will be added map1.putIfAbsent("key1", 3); // key1 already exists, so it will not be updated System.out.println("Using putIfAbsent(): " + map1); // Output: {key1=1, key2=2} // Example demonstrating computeIfAbsent() method Map<String, Integer> map2 = new HashMap<>(); map2.put("key1", 1); map2.computeIfAbsent("key2", k -> 2); // key2 does not exist, so the value is computed as 2 map2.computeIfAbsent("key1", k -> 3); // key1 already exists, so the value is not recomputed System.out.println("Using computeIfAbsent(): " + map2); // Output: {key1=1, key2=2} } }
In this code:
putIfAbsent()
method is used to add a key-value pair to the map only if the key does not already exist or is associated with anull
value.computeIfAbsent()
method is used to compute the value for a specified key if the key is not already associated with a non-null value in the map.
The output of the code is –
Using putIfAbsent(): {key1=1, key2=2} Using computeIfAbsent(): {key1=1, key2=2}
4. Comparison
Aspect | putIfAbsent() | computeIfAbsent() |
---|---|---|
Usage | Adding a key-value pair if the key does not exist or is associated with a null value. | Computing a value for a key if it is not already present in the map. |
Behavior | If the key already exists, the method does not update its value. | If the key already exists and is associated with a non-null value, the method does not compute a new value. |
Return Value | Returns the previous value associated with the key, or null if there was no mapping for the key. | Returns the current (existing or computed) value associated with the key, or null if the mapping function produces a null result. |
Performance | Fast; O(1) time complexity on average. | Depends on the complexity of the mapping function; generally slower than putIfAbsent() . |
Complexity | O(1) time complexity on average. | Depends on the complexity of the mapping function. |
Use Case | Adding default values or initializing values for keys that may not exist. | Performing complex calculations or lazy initialization of values for keys that may not exist. |
5. Conclusion
In conclusion, the concepts of lazy evaluation with “compute” and eager evaluation with “put” play crucial roles in Java programming, particularly when working with map data structures. Understanding these evaluation strategies is essential for writing efficient and optimized code.
Lazy evaluation with the computeIfAbsent()
method allows for deferred computation of values until they are needed. This can be beneficial for scenarios where the computation is expensive or the value may not always be required. By deferring the computation until necessary, resources can be saved and performance can be improved.
On the other hand, eager evaluation with the put()
method immediately computes or adds values to the map, regardless of whether they will be used immediately or not. While this ensures that the value is readily available when needed, it may lead to unnecessary computation and resource utilization, especially if the value is not always required.
Choosing the appropriate method based on the specific requirements of the application is crucial for writing efficient and optimized code. Developers should consider factors such as the frequency of value usage, computational complexity, and resource constraints when deciding between lazy and eager evaluation strategies.
Overall, by leveraging the concepts of lazy “compute” and eager “put” effectively, developers can optimize their code for better performance, resource utilization, and maintainability.