I was trying to understand CompletableFuture, and came across 2 methods, thenApplyAsync and thenCompose. Am trying to understand the difference between these two.
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " Printing hello");
return "Hello";
}).thenCompose((String s) -> {
return CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + " Adding abc");
return "abc "+s;});
}).thenApplyAsync((String s) -> {
System.out.println(Thread.currentThread().getName() + " Adding world");
return s + " World";
}).thenApplyAsync((String s) -> {
System.out.println(Thread.currentThread().getName() + " Adding name");
if (false) {
throw new RuntimeException("Oh no exception");
}
return s + " player!";
}).handle((String s, Throwable t) -> {
System.out.println(s != null ? s : "BLANK");
System.out.println(t != null ? t.getMessage() : "BLANK Exception");
return s != null ? s : t.getMessage();
});
How I interpreted these methods as, thenApplyAsync will execute the supplied function in a different thread and return a result, but internally it is wrapped inside a CompletionStage. Whereas, thenCompose will get the return a reference to a CompletionStage.
So under what scenarios, will I use thenCompose over thenApplyAsync?
Went through this link, but it was talking about thenApply, which is somewhat different:
CompletableFuture | thenApply vs thenCompose
You would use
thenComposewhen you have an operation that returns aCompletionStageandthenApplywhen you have an operation that doesn't return aCompletionStage. -> This is was is in thenApply vs thenComposeHowever the
Asyncvariants of theCompletionStageinterface have subtle difference and rare use cases.Let's take this example into account:
Which outputs something like:
Notice that
thenApplyAsyncdoesn't not affect the original future's completed state in contrast with the non async variants which do affect the completed state of theCompletionStage.Use cases:
thenComposeYou might
thenComposewhen you have 2 asynchronous operations that need to be executed sequentially:You can only retrieve the record after you inserted it.
Asyncvariants ofthenXXXXmethodsImagine for a moment that you have an application that allows users to register themselves and upon registration they will receive a confirmation email to confirm their account.
You don't want the user to be waiting for ever if the mail server is down or if it takes a long time to compose the email or perform additional checks.
You would then use
thenApplyAsyncto fire off the send email logic because it is not crucial to your system. A user can always go back and say "send me another email"Here your system will respond when the registration is complete but it will not wait for the email to be sent resulting in improved responsiveness of your system.
The uses cases I've found so far for the
Asyncvariants are scarce but they do exist.