CompletableFuture.allOf în Java

Returnează un CompletableFuture care se termină când s-au terminat toate cele primite; anyOf, când s-a terminat primul.

Sintaxă
static CompletableFuture<Void> allOf(CompletableFuture<?>... toate)
static CompletableFuture<Object> anyOf(CompletableFuture<?>... toate)

Ce face CompletableFuture.allOf

allOf(f1, f2, f3) creează un CompletableFuture<Void> care se completează abia după ce s-au completat toate cele primite. Nu adună rezultatele: după allOf(...).join() le iei din fiecare future cu join(), care acum nu mai așteaptă.

Dacă unul dintre ele eșuează, și allOf se termină cu eroare, dar abia după ce s-au terminat toate. anyOf se completează cu rezultatul primului future terminat.

Modelul obișnuit cu o listă: allOf(lista.toArray(new CompletableFuture<?>[0])), apoi lista.stream().map(CompletableFuture::join).toList().

Parametri

Parametru Descriere
toate Unul sau mai multe CompletableFuture, sau un tablou de ele.

Ce returnează

allOf: CompletableFuture<Void>. anyOf: CompletableFuture<Object> cu rezultatul primului terminat.

Exemple

Exemplul 1: Temperaturile din mai multe orașe

Toate cererile pornesc odată. După allOf, rezultatele se citesc în ordinea listei.

import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

public class Main {
    static final Map<String, Integer> TEMPERATURI = Map.of("Iași", 14, "Cluj", 11, "Constanța", 17, "Brașov", 9);

    static int temperatura(String oras) {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return TEMPERATURI.get(oras);
    }

    public static void main(String[] args) {
        List<String> orase = List.of("Iași", "Cluj", "Constanța", "Brașov");
        List<CompletableFuture<Integer>> cereri = orase.stream()
            .map(o -> CompletableFuture.supplyAsync(() -> temperatura(o)))
            .toList();
        CompletableFuture.allOf(cereri.toArray(new CompletableFuture<?>[0])).join();
        List<Integer> valori = cereri.stream().map(CompletableFuture::join).toList();
        for (int i = 0; i < orase.size(); i++) {
            System.out.println(orase.get(i) + ": " + valori.get(i) + "°C");
        }
    }
}

Rezultat

Iași: 14°C
Cluj: 11°C
Constanța: 17°C
Brașov: 9°C

Exemplul 2: anyOf: primul răspuns

import java.util.concurrent.CompletableFuture;

public class Main {
    static CompletableFuture<String> oglinda(String nume, int ms) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(ms);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "descărcat de pe " + nume;
        });
    }

    public static void main(String[] args) {
        Object primul = CompletableFuture.anyOf(oglinda("ro.mirror", 100), oglinda("de.mirror", 800)).join();
        System.out.println(primul);
    }
}

Rezultat

descărcat de pe ro.mirror

Exemplul 3: O sarcină eșuată face allOf să eșueze

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

public class Main {
    public static void main(String[] args) {
        CompletableFuture<Integer> a = CompletableFuture.supplyAsync(() -> 10);
        int zero = 0;
        CompletableFuture<Integer> b = CompletableFuture.supplyAsync(() -> 10 / zero);
        try {
            CompletableFuture.allOf(a, b).join();
        } catch (CompletionException e) {
            System.out.println("allOf a eșuat: " + e.getCause().getMessage());
        }
        System.out.println("a s-a terminat normal: " + a.join());
    }
}

Rezultat

allOf a eșuat: / by zero
a s-a terminat normal: 10

Greșeli frecvente

  • Aștepți ca allOf(...).join() să returneze rezultatele. Returnează null (tipul Void); rezultatele le iei din fiecare future.
  • Scrii toArray(new CompletableFuture[0]). Este un tip „raw” și javac -Xlint avertizează; folosește new CompletableFuture<?>[0].

Comenzi înrudite

  • CompletableFuture.thenCombine: Combină rezultatele a două CompletableFuture independente, după ce sunt gata amândouă.
  • CompletableFuture.supplyAsync: Pornește o sarcină pe alt fir și returnează imediat un CompletableFuture; supplyAsync are rezultat, runAsync nu.
  • ExecutorService.invokeAll: Trimite o listă de sarcini și așteaptă să se termine toate; returnează lista de Future în aceeași ordine.
  • CompletableFuture: Un Future care se poate înlănțui: definești ce se întâmplă cu rezultatul (thenApply, thenAccept) fără să aștepți; join() îl ia la final.