Composing CompletableFuture
Chain and combine async steps without blocking, and recover cleanly when one of them fails.
Open this lesson in the learning hubKey points
supplyAsyncstarts work and returns immediately. Nothing blocks until you ask for the value.thenApplytransforms a result.thenComposeis flatMap: use it when the next step is itself async, or you get a nested future.thenCombinemerges two independent futures so both run in parallel.allOfwaits for a whole batch.exceptionallyandhandlerecover from failure. The exception arrives wrapped inCompletionException, so unwrap withgetCause().- The default executor is the common ForkJoinPool. Never do blocking I/O there. Pass your own executor to the
*Asyncoverloads. join()isget()without checked exceptions. Call it once, at the very edge of your code.
Example
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
CompletableFuture<String> user = CompletableFuture.supplyAsync(() -> { sleep(100); return "ada"; });
CompletableFuture<Integer> count = CompletableFuture.supplyAsync(() -> { sleep(100); return 3; });
// two independent calls, run in parallel, merged at the end
System.out.println(user.thenCombine(count, (u, c) -> u + " has " + c + " orders").join());
// dependent steps: transform, then call something that is also async
String greeting = CompletableFuture.supplyAsync(() -> "ada")
.thenApply(String::toUpperCase)
.thenCompose(name -> CompletableFuture.supplyAsync(() -> "hello " + name))
.join();
System.out.println(greeting);
// recover instead of blowing up
String safe = CompletableFuture.<String>supplyAsync(() -> { throw new IllegalStateException("timeout"); })
.exceptionally(ex -> "fallback: " + ex.getCause().getMessage())
.join();
System.out.println(safe);
}
static void sleep(long ms) {
try { Thread.sleep(ms); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
}
Describe the whole pipeline first, then block exactly once, at the end.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Multithreading course, and every lesson in it is listed on the Multithreading contents page.