computeIfPresent() is a Map method introduced in Java 8 that conditionally updates a value using a function — but only if the key already exists in the map. If the key is absent, nothing happens. It replaces the verbose containsKey() + put() pattern with a single, expressive call.
Method Signature
V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)
- key — the key to look up
- remappingFunction — receives the key and current value; its return value becomes the new value
- Returns — the new value if key was present;
nullif absent or function returnednull - Side effect — if the function returns
null, the entry is removed from the map
Basic Example
import java.util.HashMap;
import java.util.Map;
public class ComputeIfPresentExample {
public static void main(String[] args) {
Map<String, Integer> prices = new HashMap<>();
prices.put("Sunglasses", 105);
prices.put("Watch", 1501);
prices.put("Wallet", 299);
System.out.println("Before: " + prices);
// "Watch" exists — price is doubled
prices.computeIfPresent("Watch", (key, value) -> value * 2);
// "Bag" doesn't exist — map is unchanged
prices.computeIfPresent("Bag", (key, value) -> value * 2);
System.out.println("After: " + prices);
// {Watch=3002, Sunglasses=105, Wallet=299}
}
}
Output:
Before: {Watch=1501, Sunglasses=105, Wallet=299}
After: {Watch=3002, Sunglasses=105, Wallet=299}
Removing an Entry by Returning null
If the remapping function returns null, the entry is deleted:
Map<String, Integer> stock = new HashMap<>();
stock.put("Apples", 10);
stock.put("Bananas", 5);
stock.put("Cherries", 20);
// Remove items with stock below 8
stock.computeIfPresent("Apples", (k, v) -> v < 8 ? null : v); // 10 >= 8, kept
stock.computeIfPresent("Bananas", (k, v) -> v < 8 ? null : v); // 5 < 8, removed
stock.computeIfPresent("Cherries", (k, v) -> v < 8 ? null : v); // 20 >= 8, kept
System.out.println(stock);
// {Apples=10, Cherries=20}
Before vs. After Java 8
Old approach — three lines, two map lookups:
if (prices.containsKey("Watch")) {
prices.put("Watch", prices.get("Watch") * 2);
}
Modern approach — one line, atomic:
prices.computeIfPresent("Watch", (k, v) -> v * 2);
Beyond being cleaner, the modern approach is also atomic on ConcurrentHashMap, which makes it correct under concurrent access — the old pattern is not.
Real-World Example: Updating a Frequency Map
Map<String, Integer> wordCount = new HashMap<>();
wordCount.put("java", 5);
wordCount.put("python", 3);
wordCount.put("kotlin", 7);
String[] wordsToUpdate = {"java", "rust", "python", "go"};
for (String word : wordsToUpdate) {
wordCount.computeIfPresent(word, (k, v) -> v + 1);
}
System.out.println(wordCount);
// {java=6, python=4, kotlin=7} — "rust" and "go" were NOT added
Real-World Example: Applying a Selective Discount
Map<String, Double> cart = new HashMap<>();
cart.put("Laptop", 999.99);
cart.put("Mouse", 29.99);
cart.put("Keyboard", 79.99);
cart.put("Monitor", 349.99);
List<String> saleItems = List.of("Mouse", "Keyboard", "Headphones");
for (String item : saleItems) {
// Apply 20% discount — "Headphones" not in cart, skipped
cart.computeIfPresent(item, (k, v) -> Math.round(v * 0.8 * 100.0) / 100.0);
}
cart.forEach((item, price) ->
System.out.printf("%-12s $%.2f%n", item, price));
// Laptop $999.99
// Mouse $23.99
// Keyboard $63.99
// Monitor $349.99
Thread-Safe Use with ConcurrentHashMap
computeIfPresent() is atomic on ConcurrentHashMap. The check and the update happen as a single operation — no other thread can modify the entry between them:
import java.util.concurrent.ConcurrentHashMap;
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("counter", 0);
// Safe to call from multiple threads concurrently
concurrentMap.computeIfPresent("counter", (k, v) -> v + 1);
The old containsKey() + put() pattern is not thread-safe — another thread can insert or remove the key between your two calls.
Related Map Compute Methods
| Method | When to Use |
|---|---|
computeIfPresent(k, fn) | Update an existing value; do nothing if key absent |
computeIfAbsent(k, fn) | Insert a new value; do nothing if key present |
compute(k, fn) | Always call fn; fn receives null if key absent |
merge(k, v, fn) | Combine a new value with an existing one, or insert if absent |
put(k, v) | Always set a value, regardless of whether key exists |
putIfAbsent(k, v) | Insert only if key absent; fixed value (no function) |
Summary
Use computeIfPresent() when you need to update an existing map entry based on its current value, without the boilerplate of a containsKey() check. It's cleaner, more expressive, and thread-safe when used with ConcurrentHashMap.
No comments :
Post a Comment
Please leave your message queries or suggetions.
Note: Only a member of this blog may post a comment.