ComputeIfPresent Example in Java

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; null if absent or function returned null
  • 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

MethodWhen 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.