Working with CompletableFuture

1. Creating CompletableFuture

FactoryUse
completedFuture(v)Already done
failedFuture(t)Already failed (Java 9+)
supplyAsync(Supplier[, exec])Async producer
runAsync(Runnable[, exec])Async void
Manualnew CompletableFuture<>() + complete

2. Chaining Async Operations

MethodFunction TypeResult
thenApplyFunction<T,U>CF<U>
thenAcceptConsumer<T>CF<Void>
thenRunRunnableCF<Void>
thenComposeFunction<T,CF<U>>CF<U> (flatMap)

3. Combining Futures

MethodBehavior
thenCombine(other, fn)Both complete → combine
thenAcceptBothBoth → consumer
runAfterBothBoth → runnable
applyToEitherFirst done → fn
acceptEitherFirst done → consumer

4. Handling Errors

MethodUse
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)

FormWhere it Runs
thenApply(fn)Caller or completer thread
thenApplyAsync(fn)commonPool
thenApplyAsync(fn, exec)Custom executor

6. Waiting for Completion

MethodThrows
get()InterruptedException, ExecutionException
get(t, unit)+ TimeoutException
join()Unchecked CompletionException
getNow(default)Non-blocking

7. Combining Multiple Futures

APIUse
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

ReasonDetail
IsolationAvoid commonPool starvation
Bounded queueBack-pressure
NamingTracing/monitoring
Virtual threadsExecutors.newVirtualThreadPerTaskExecutor()

9. Understanding Exception Propagation

StageBehavior
Failure in upstreamSkips dependent thenX stages
Wraps inCompletionException (cause = original)
whenCompleteAlways runs, doesn't recover
handleRecovers (returns new value)

10. Using CompletionStage Interface

AspectDetail
InterfaceImplemented by CompletableFuture
UseAPI parameter to avoid completion control leak
toCompletableFuture()Get back CF view

11. Creating Timeout Handling

MethodBehavior
orTimeout(t, unit) Java 9+Fails with TimeoutException
completeOnTimeout(v, t, unit)Default value on timeout
delayedExecutor(t, unit)Schedule with delay

Example: With timeout + fallback

CompletableFuture<String> result = client.callAsync(req)
    .orTimeout(2, TimeUnit.SECONDS)
    .exceptionally(t -> "fallback");