Java · OOP, JVM and backend craft
How does CompletableFuture support asynchronous composition?
Short answer
CompletableFuture composes asynchronous work through callbacks and combinators. It supports chaining, combining, fallbacks and fan-out without blocking a thread per step.
A CompletableFuture represents a result that will exist later. You attach dependent stages with thenApply, thenCompose and thenCombine, and handle failure with exceptionally or handle. The default async methods run on the common ForkJoinPool unless you pass an executor.
CompletableFuture<String> result =
CompletableFuture.supplyAsync(() -> fetchUser(userId), executor)
.thenCompose(user -> fetchOrders(user))
.thenApply(orders -> summarize(orders))
.exceptionally(error -> "fallback");
String value = result.join();The combinators that matter
- thenApply transforms a result synchronously; thenCompose chains another async stage
- thenCombine merges two independent futures when both complete
- allOf waits for all futures; anyOf completes with the first success
- exceptionally and handle recover; whenComplete observes without changing the value
- orTimeout and completeOnTimeout bound how long a stage may take
Use a custom executor for blocking IO. The common pool is sized for CPU work, and blocking its threads can starve unrelated tasks. Also avoid calling join on a request thread without a timeout, because that reintroduces the blocking you were trying to remove.
Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1What is the difference between thenApply and thenCompose?
- 2How do you combine two independent futures?
- 3Why use a custom executor with CompletableFuture?
- 4How do you add a timeout to an async stage?
Say it in the interview
CompletableFuture represents an asynchronous result and lets me compose stages without blocking. thenApply transforms a value, thenCompose chains another async call, and thenCombine merges independent results. I handle failures with exceptionally or handle and add timeouts for external calls. For blocking IO I pass a dedicated executor, because the common pool is sized for CPU work and should not be starved by blocking tasks.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Java mock interview and get scored feedback on depth, clarity and confidence.