Map.computeIfAbsent în Java

Dacă cheia lipsește, calculează valoarea cu funcția dată și o pune în map. Returnează valoarea (nouă sau existentă). Ideal pentru grupări.

Sintaxă
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

Ce face Map.computeIfAbsent

computeIfAbsent(cheie, k -> valoare) apelează funcția doar dacă cheia lipsește (sau are null), pune rezultatul în map și îl returnează. Dacă cheia există, returnează valoarea existentă fără să apeleze funcția.

Cea mai cunoscută folosire este gruparea: map.computeIfAbsent(clasa, k -> new ArrayList<>()).add(elev). Prima dată creează lista goală, apoi o returnează pe aceeași de fiecare dată.

Este potrivită și ca un cache simplu: rezultatul unui calcul costisitor se calculează o dată și se păstrează. Dacă funcția returnează null, nu se adaugă nimic.

Parametri

Parametru Descriere
key Cheia.
mappingFunction Funcția care primește cheia și creează valoarea.

Ce returnează

Valoarea asociată cheii după apel (sau null).

Exemple

Exemplul 1: Gruparea cuvintelor după prima literă

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class Main {
    public static void main(String[] args) {
        String[] orase = {"Iași", "Arad", "Cluj", "Alba Iulia", "Craiova", "Ilfov"};
        Map<Character, List<String>> grupe = new TreeMap<>();
        for (String o : orase) {
            grupe.computeIfAbsent(o.charAt(0), k -> new ArrayList<>()).add(o);
        }
        System.out.println(grupe);
    }
}

Rezultat

{A=[Arad, Alba Iulia], C=[Cluj, Craiova], I=[Iași, Ilfov]}

Exemplul 2: Calcul făcut o singură dată (cache)

Mesajul „calculez” apare o singură dată pentru fiecare număr.

import java.util.HashMap;
import java.util.Map;

public class Main {
    static final Map<Integer, Long> cache = new HashMap<>();

    static long factorial(int n) {
        return cache.computeIfAbsent(n, k -> {
            System.out.println("calculez " + k + "!");
            long f = 1;
            for (int i = 2; i <= k; i++) {
                f *= i;
            }
            return f;
        });
    }

    public static void main(String[] args) {
        System.out.println(factorial(10));
        System.out.println(factorial(10));
        System.out.println(factorial(5));
    }
}

Rezultat

calculez 10!
3628800
3628800
calculez 5!
120

Greșeli frecvente

  • În funcție apelezi recursiv computeIfAbsent pe același map (de exemplu Fibonacci recursiv). HashMap aruncă ConcurrentModificationException.
  • Folosești computeIfAbsent pentru numărare. Pentru contoare, merge(k, 1, Integer::sum) e mai potrivit.

Comenzi înrudite

  • Map.compute: compute recalculează valoarea unei chei pornind de la cea veche (sau null); computeIfPresent o face doar dacă cheia există.
  • Map.putIfAbsent: Pune valoarea doar dacă cheia lipsește (sau are null). Nu suprascrie o valoare existentă; returnează valoarea care era deja.
  • 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.
  • HashMap: Dicționarul cel mai rapid: put, get și remove în timp aproape constant, dar fără ordine garantată a cheilor.