Working with CompletableFuture
1. Creating CompletableFuture
| Factory | Use |
|---|---|
completedFuture(v) | Already done |
failedFuture(t) | Already failed (Java 9+) |
supplyAsync(Supplier[, exec]) | Async producer |
runAsync(Runnable[, exec]) | Async void |
| Manual | new CompletableFuture<>() + complete |
2. Chaining Async Operations
| Method | Function Type | Result |
|---|---|---|
thenApply | Function<T,U> | CF<U> |
thenAccept | Consumer<T> | CF<Void> |
thenRun | Runnable | CF<Void> |
thenCompose | Function<T,CF<U>> | CF<U> (flatMap) |
3. Combining Futures
| Method | Behavior |
|---|---|
thenCombine(other, fn) | Both complete → combine |
thenAcceptBoth | Both → consumer |
runAfterBoth | Both → runnable |
applyToEither | First done → fn |
acceptEither | First done → consumer |
4. Handling Errors
| Method | Use |
|---|---|
exceptionally(Function<Throwable,T>) | Recover with value |
handle((v, t) -> ...) | Inspect both result and error |
whenComplete((v, t) -> ...) | Side effect, propagates |
exceptionallyCompose Java 12+ | Async recovery |
5. Using Async Variants (thenApplyAsync)
| Form | Where it Runs |
|---|---|
thenApply(fn) | Caller or completer thread |
thenApplyAsync(fn) | commonPool |
thenApplyAsync(fn, exec) | Custom executor |
6. Waiting for Completion
| Method | Throws |
|---|---|
get() | InterruptedException, ExecutionException |
get(t, unit) | + TimeoutException |
join() | Unchecked CompletionException |
getNow(default) | Non-blocking |
7. Combining Multiple Futures
| API | Use |
|---|---|
allOf(cfs...) | CF<Void>; completes when all done |
anyOf(cfs...) | CF<Object>; completes when first done |
Example: Aggregate results
List<CompletableFuture<User>> futures = ids.stream().map(repo::findAsync).toList();
CompletableFuture<List<User>> all = CompletableFuture
.allOf(futures.toArray(CompletableFuture[]::new))
.thenApply(v -> futures.stream().map(CompletableFuture::join).toList());
8. Using Custom Executors
| Reason | Detail |
|---|---|
| Isolation | Avoid commonPool starvation |
| Bounded queue | Back-pressure |
| Naming | Tracing/monitoring |
| Virtual threads | Executors.newVirtualThreadPerTaskExecutor() |
9. Understanding Exception Propagation
| Stage | Behavior |
|---|---|
| Failure in upstream | Skips dependent thenX stages |
| Wraps in | CompletionException (cause = original) |
| whenComplete | Always runs, doesn't recover |
| handle | Recovers (returns new value) |
10. Using CompletionStage Interface
| Aspect | Detail |
|---|---|
| Interface | Implemented by CompletableFuture |
| Use | API parameter to avoid completion control leak |
toCompletableFuture() | Get back CF view |
11. Creating Timeout Handling
| Method | Behavior |
|---|---|
orTimeout(t, unit) Java 9+ | Fails with TimeoutException |
completeOnTimeout(v, t, unit) | Default value on timeout |
delayedExecutor(t, unit) | Schedule with delay |