You can use the following methods to handle exceptions in Java 8+ CompletableFuture
Java 8+
handle
, andhandleAsync
Java 8+
exceptionally
, and Java 12+exceptionallyAsync
Java 8+
whenComplete
, andwhenCompleteAsync
The stage created by exceptionally
/exceptionallyAsync
and whenComplete
/whenCompleteAsync
can only be executed when there're exceptions in the previous stages, while by handle
/handleAsync
, it can be executed in both normal and exception cases
Let's walk through this tutorial to explore them in more details
Use handle(BiFunction) and handleAsync(BiFunction)
handle
and handleAsync
are used for handling exceptions and translate completion outcomes. The stage created by them can be executed in either the previous stages have exceptions or not
They accept a BiFunction with (result, exception)
as arguments received from the preceding stage, and complete its stage with the return value from BiFunction
In the following example, handleAsync
received NumberFormatException
caused by Integer.parseInt("s")
in supplyAsync
, it prints out the error message and returns Error!
to the next stage thenAcceptAsync
CompletableFuture completableFuture = CompletableFuture
.supplyAsync(() -> Integer.parseInt("s"))
.handleAsync((result, e) -> {
if (e != null) {
System.out.println(e.getMessage());
return "Error!";
} else {
return result + 1;
}
})
.thenAcceptAsync(System.out::println);
Output
java.lang.NumberFormatException: For input string: "s"
Error!
In this example, handleAsync
is still executed, although there are no exceptions in the previous stages
CompletableFuture completableFuture = CompletableFuture
.supplyAsync(() -> 1)
.handleAsync((result, e) -> {
if (e != null) {
System.out.println(e.getMessage());
return "Error!";
} else {
return result + 1;
}
})
.thenAcceptAsync(System.out::println);
Output
2
Use exceptionally(Function) and exceptionallyAsync(Function)
Unlike handle
and handleAsync
, the stage created by exceptionally
and exceptionallyAsync
only executed when there're exceptions in the previous stages. Apart from that, the return value from them have to be null or the same type as the preceding stage
exceptionally
and exceptionallyAsync
accept a Function
with (exception)
as the only argument
In the below example, exceptionallyAsync
received NumberFormatException
caused by Integer.parseInt("s")
in supplyAsync
, it prints out the error message and returns 0
to the next stage thenAcceptAsync
CompletableFuture completableFuture = CompletableFuture
.supplyAsync(() -> Integer.parseInt("s"))
.exceptionallyAsync((e) -> {
System.out.println(e.getMessage());
return 0;
})
.thenAcceptAsync(System.out::println);
Output
java.lang.NumberFormatException: For input string: "s"
0
In this example, exceptionallyAsync
is not executed, as there're no exceptions from previous stages
CompletableFuture completableFuture = CompletableFuture
.supplyAsync(() -> 1)
.exceptionallyAsync((e) -> {
System.out.println(e.getMessage());
return 0;
})
.thenAcceptAsync(System.out::println);
Output
1
Use whenComplete(BiConsumer) and whenCompleteAsync(BiConsumer)
whenComplete
and whenCompleteAsync
accept a BiConsumer
with (result, exception)
as the arguments
Different from handle
and handleAsync
, whenComplete
and whenCompleteAsync
are not used for translating completion outcomes (return no value). The stage created by them are only executed when there're exceptions in the previous stages
In the following example, whenCompleteAsync
received NumberFormatException
caused by Integer.parseInt("s")
in supplyAsync
, and prints out the error message
CompletableFuture completableFuture = CompletableFuture
.supplyAsync(() -> Integer.parseInt("s"))
.whenCompleteAsync((result, e) -> {
if (e != null) System.out.println(e.getMessage());
})
.thenAcceptAsync(System.out::println);
Output
java.lang.NumberFormatException: For input string: "s"
In this example, whenCompleteAsync
is not executed, as there're no exceptions from previous stages
CompletableFuture completableFuture = CompletableFuture
.supplyAsync(() -> 1)
.whenCompleteAsync((result, e) -> {
if (e != null) System.out.println(e.getMessage());
})
.thenAcceptAsync(System.out::println);
Output
1
Conclusion
In this article, we learned to handle exceptions in Java CompletableFuture by using handle
, handleAsync
, exceptionally
, exceptionallyAsync
, whenComplete
and whenCompleteAsync
. You can find the full source code as below