All topics
library
advanced

CompletableFuture for Async Programming

Compose asynchronous operations with CompletableFuture's fluent API instead of blocking with Future.get().

CompletableFuture (Java 8) is a non-blocking, composable alternative to Future. It supports chaining, combining, and error handling for async operations.

Future.get() = ordering food and standing at the counter waiting. CompletableFuture = ordering food and getting a buzzer — you do other things until it buzzes, then you pick up your meal and eat it (thenAccept).

Key Concepts

1
Creation: - CompletableFuture.supplyAsync(() -> compute()) — runs in ForkJoinPool.commonPool() - CompletableFuture.supplyAsync(() -> compute(), executor) — custom executor - CompletableFuture.completedFuture(value) — already completed
2
Chaining (non-blocking): - thenApply(fn): transform result (like map) - thenAccept(consumer): consume result, return void - thenCompose(fn): chain another CompletableFuture (like flatMap) - thenRun(runnable): run action after completion
3
Combining: - thenCombine(otherFuture, biFunction): combine two futures - allOf(cf1, cf2, cf3): wait for all to complete - anyOf(cf1, cf2, cf3): first to complete wins
4
Error handling: - exceptionally(fn): handle exception, return fallback - handle(biFunction): handle both success and failure - whenComplete(biConsumer): observe result/exception without changing it
5
Async variants: thenApplyAsync, thenAcceptAsync — run the callback in the thread pool instead of the completing thread. Use when the callback is CPU-heavy.
6
Virtual threads (Java 21): combine CompletableFuture with virtual thread executors for massive concurrency without blocking thread pool threads.