I can\'t get my head around the difference between thenApply(
) and thenCompose()
.
So, could someone provide a valid use case?
Fro
thenCompose() is better for chaining CompletableFuture.
thenApply() is better for transform result of Completable future.
You can achieve your goal using both techniques, but one is more suitable for one use case then other.
public CompletableFuture process(Integer i) {
CompletableFuture completableFuture = CompletableFuture.supplyAsync(
() -> new HeavyTask(i).execute());
return completableFuture;
}
@SneakyThrows
public CompletableFuture thenApplyVsThenCompose() {
// each time calling thenApply() function returns CompletionState
// so you will get nested Futures
// you can think about it like map() java optional
CompletableFuture> cf1 = CompletableFuture.supplyAsync(
() -> new HeavyTask().execute())
.thenApply(i -> process(i));
// to get result you will have to get nested get() calls
Integer resultFromThenApply = cf1.get().get();
// when calling thenCompose() nested Futures are flatten
// you can think about it like flatMap() java optional
CompletableFuture cf2;
cf2 = CompletableFuture.supplyAsync(
() -> new HeavyTask().execute())
.thenCompose(this::process);
// you have to just call one get() since thenCompose was flatten
Integer resultFromThenCompose = cf2.get();
return null;
}
Other problem that can visualize difference between those two
How would you implement solution when you do not know how many time you have to apply thenApply()/thenCompose() (in case for example recursive methods)?
public void nested() throws ExecutionException, InterruptedException {
CompletableFuture completableFutureToCompose = CompletableFuture.completedFuture(1);
for (int i = 0; i < 10; i++) {
log.info("Composing");
completableFutureToCompose = completableFutureToCompose.thenCompose(this::process);
}
completableFutureToCompose.get();
// not achievable using then apply
CompletableFuture completableFutureToApply = CompletableFuture.completedFuture(1);
for (int i = 0; i < 10; i++) {
log.info("Applying");
completableFutureToApply = completableFutureToApply.thenApply(this::process).get();
}
completableFutureToCompose.get();
}
public CompletableFuture process(Integer i) {
log.info("PROCESSING");
CompletableFuture completableFuture = CompletableFuture.supplyAsync(
() -> new HeavyTask(i).execute());
return completableFuture;
}