I am trying to set a default value when exceptions happen in CompletableFuture
I made it work by handle
method as follows:
private static void testHandle() {
String name = null;
CompletableFuture<String> completableFuture
= CompletableFuture.supplyAsync(() -> {
if (name == null) {
throw new RuntimeException("Computation error!");
}
return "Hello, " + name;
}).handle((s, t) -> s != null ? s : "Hello, Stranger!" + t.toString());
out.println(completableFuture.join());
}
But when I tried to stop the CompletableFuture
using completeExceptionally
when bad things happen and track the exception as follows I cannot catch the exception as I did just now.
private static void testCompleteExceptionally() {
String name = "Hearen";
CompletableFuture<String> completableFuture
= CompletableFuture.supplyAsync(() -> {
delay(500L);
if (name == null) {
throw new RuntimeException("Computation error!");
}
return "Hello, " + name;
}).handle((s, t) -> {
try {
throw t.getCause();
} catch (Throwable e) {
out.println(e.toString()); // I was hoping to record the custom exceptions here;
}
return s != null ? s : "Hello, Stranger!" + t.toString();
});
if (name != null) {
completableFuture.completeExceptionally(new RuntimeException("Calculation failed!")); // when bad things happen, I try to complete it by exception;
}
out.println(completableFuture.join());
}
UPDATED 2018-06-09 Thanks for the help, @Daniele
private static void testCompleteExceptionally() {
String name = "Hearen";
CompletableFuture<String> completableFuture
= CompletableFuture.supplyAsync(() -> {
delay(500L);
if (name == null) {
throw new RuntimeException("Computation error!");
}
return "Hello, " + name;
});
if (name != null) {
completableFuture.completeExceptionally(new RuntimeException("Calculation failed!"));
}
out.println(completableFuture.handle((s, t) -> s != null ? s : "Hello, Stranger!" + t.toString()).join());
}
The handle enclosed just before join()
works as expected. But in this case, the returned value
will be null
.
Based on the handle API
Returns a new CompletionStage that, when this stage completes either normally or exceptionally, is executed with this stage's result and exception as arguments to the supplied function.
Best Answer
You are building a
future
, piping with anhandle
(so getting another future) and then completing exceptionally the future returned by thehandle
.You should complete exceptionally the inner
future
itself, instead of thehandle
.The point here is that
handle
returns another future; and you should not complete the "outer" future exceptionally, because doing that will bypass the handling behavior.Below the code;