User problem: Compute the total of an order. If something goes wrong then throw an IllegalStateException.
Sometimes we want to execute an exceptional block of code even if an exception did not occur. Like the finally clause of a try-catch block. This is possible using the handle() callback. This method is called whether or not an exception occurred, and is somehow like a catch + finally. It takes a function used to compute the value of the returned CompletionStage, BiFunction<? super T,Throwable,? extends U> and returns CompletionStage<U> (U is the function's return type).
Let's see it at work:
public static void fetchOrderTotalHandle() {
CompletableFuture<Integer> totalOrder
= CompletableFuture.supplyAsync(() -> {
logger.info(() -> "Compute total by: "
+ Thread.currentThread().getName());
int surrogate = new Random().nextInt(1000);
if (surrogate < 500) {
throw new IllegalStateException(
"Computing service is not responding");
}
return 1000;
}).handle((res, ex) -> {
if (ex != null) {
logger.severe(() -> "Exception: " + ex
+ " Thread: " + Thread.currentThread().getName());
return 0;
}
if (res != null) {
int vat = res * 24 / 100;
res += vat;
}
return res;
});
int result = totalOrder.get();
logger.info(() -> "Total: " + result + " ");
}
Notice that res will be null; otherwise, the ex will be null if an exception occurs.
If we need to complete with an exception, then we can proceed via completeExceptionally() as in the following example:
CompletableFuture<Integer> cf = new CompletableFuture<>();
...
cf.completeExceptionally(new RuntimeException("Ops!"));
...
cf.get(); // ExecutionException : RuntimeException
Canceling the execution and throwing CancellationException can be done via the cancel() method:
CompletableFuture<Integer> cf = new CompletableFuture<>();
...
// is not important if the argument is set to true or false
cf.cancel(true/false);
...
cf.get(); // CancellationException