Map.compute în Java

compute recalculează valoarea unei chei pornind de la cea veche (sau null); computeIfPresent o face doar dacă cheia există.

Sintaxă
default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remapping)
default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remapping)

Ce face Map.compute

compute(cheie, (k, vechi) -> nou) apelează funcția cu cheia și valoarea actuală (null dacă cheia lipsește) și pune rezultatul ca valoare nouă. Dacă funcția returnează null, perechea este ștearsă (sau nu se adaugă).

computeIfPresent apelează funcția doar dacă cheia există și are o valoare diferită de null; altfel nu face nimic. Este utilă pentru „scade stocul, iar dacă ajunge la zero, scoate produsul”.

Pentru cazul „adaugă dacă lipsește” există computeIfAbsent, iar pentru „combină cu o valoare nouă” merge, de obicei mai scurt.

Parametri

Parametru Descriere
key Cheia.
remapping Funcția care primește cheia și valoarea veche și returnează valoarea nouă (sau null pentru ștergere).

Ce returnează

Valoarea nouă sau null.

Exemple

Exemplul 1: Contor de vizite cu compute

import java.util.Map;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> vizite = new TreeMap<>();
        for (String pagina : new String[] {"acasă", "produse", "acasă", "contact", "acasă"}) {
            vizite.compute(pagina, (p, n) -> n == null ? 1 : n + 1);
        }
        System.out.println(vizite);
    }
}

Rezultat

{acasă=3, contact=1, produse=1}

Exemplul 2: Scăderea stocului cu computeIfPresent

Când stocul ajunge la 0, funcția returnează null și produsul dispare. Pentru un produs inexistent nu se întâmplă nimic.

import java.util.Map;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) {
        Map<String, Integer> stoc = new TreeMap<>(Map.of("caiet", 2, "pix", 10));
        for (String vandut : new String[] {"caiet", "pix", "caiet", "radieră"}) {
            Integer rest = stoc.computeIfPresent(vandut, (p, n) -> n > 1 ? n - 1 : null);
            System.out.println("Vândut " + vandut + ", rămas: " + rest);
        }
        System.out.println(stoc);
    }
}

Rezultat

Vândut caiet, rămas: 1
Vândut pix, rămas: 9
Vândut caiet, rămas: null
Vândut radieră, rămas: null
{pix=9}

Greșeli frecvente

  • În compute uiți că valoarea veche poate fi null și scrii n + 1. Pentru o cheie nouă apare NullPointerException.
  • Modifici map-ul (alt put) în interiorul funcției. Comportamentul nu este definit; HashMap aruncă ConcurrentModificationException.

Comenzi înrudite

  • Map.computeIfAbsent: Dacă cheia lipsește, calculează valoarea cu funcția dată și o pune în map. Returnează valoarea (nouă sau existentă). Ideal pentru grupări.
  • Map.merge: Pune valoarea dacă cheia lipsește; dacă există, combină valoarea veche cu cea nouă (de exemplu le adună). Ideal pentru numărători și totaluri.
  • Map.replace: replace schimbă valoarea unei chei doar dacă cheia există; replaceAll recalculează toate valorile cu o funcție.
  • Map.get: get returnează valoarea unei chei sau null dacă lipsește; getOrDefault returnează o valoare de rezervă în loc de null.