How do you handle exceptions with CompletableFuture?

Table of Contents

Introduction

Handling exceptions properly is crucial when working with asynchronous tasks in Java, especially when using **CompletableFuture** for concurrency. **CompletableFuture** allows you to perform tasks asynchronously without blocking the main thread, but it also introduces challenges in managing exceptions that occur during task execution.

In this guide, we’ll explore various methods provided by **CompletableFuture** to handle exceptions, including **exceptionally()**, **handle()**, and **whenComplete()**. Understanding these methods will help you write more robust, error-resistant asynchronous code.

Methods to Handle Exceptions in CompletableFuture

1. Using the exceptionally() Method

The **exceptionally()** method allows you to handle exceptions that occur in a **CompletableFuture**. If the asynchronous task throws an exception, **exceptionally()** provides a way to define a fallback or default value to return.

This method is helpful when you want to provide a default value or alternative result if an exception occurs during the execution of the future.

Syntax:

Example: Handling an Exception with exceptionally()

Output:

In this example, the **exceptionally()** method catches the exception thrown by the asynchronous task and returns a default value (-1) instead of the result.

2. Using the handle() Method

The **handle()** method is more flexible than **exceptionally()** because it allows you to handle both the result and the exception in the same callback. This method provides a way to process the result if the computation is successful or handle the exception if the task fails.

Syntax:

  • The first argument of the **BiFunction** is the result of the **CompletableFuture** if it completes normally.
  • The second argument is the exception if one was thrown during execution.

Example: Handling Both Result and Exception with handle()

Output:

In this case, **handle()** catches the exception, and the program returns a fallback value (-1). If no exception had been thrown, the result would have been processed as normal.

3. Using the whenComplete() Method

The **whenComplete()** method is another way to handle exceptions, but with one key difference: it allows you to execute code after the **CompletableFuture** has completed, regardless of whether it was successful or exceptional. The **whenComplete()** method provides access to both the result and the exception (if any).

Unlike **handle()**, **whenComplete()** doesn’t modify the result or exception; it simply allows you to perform side effects or logging.

Syntax:

  • The **BiConsumer** has two arguments: the result (if the task completes successfully) and the exception (if an exception was thrown).

Example: Using whenComplete() for Logging

Output:

In this example, **whenComplete()** logs the error but does not alter the result or handle it like **exceptionally()** or **handle()**. This method is suitable for logging or performing some side effects, like resource cleanup.

4. Using completeExceptionally() to Manually Complete with an Exception

In some cases, you might want to manually complete a **CompletableFuture** with an exception. The **completeExceptionally()** method can be used to set the exception for the future.

Example: Manually Completing with an Exception

Output:

Here, we manually complete the future with an exception using **completeExceptionally()**, and then use **exceptionally()** to handle the error.

Conclusion

Handling exceptions properly in **CompletableFuture** is essential for writing robust, fault-tolerant asynchronous code. The Java **CompletableFuture** API provides several methods to handle errors, including **exceptionally()**, **handle()**, **whenComplete()**, and **completeExceptionally()**.

  • **exceptionally()** allows you to provide fallback values when errors occur.
  • **handle()** offers flexibility to handle both successful results and exceptions.
  • **whenComplete()** enables side-effect actions but doesn't modify the result or exception.
  • **completeExceptionally()** allows for manual completion of a future with an exception.

By using these methods effectively, you can ensure that your asynchronous tasks are resilient to errors and that your code executes smoothly even when faced with unexpected situations.

Similar Questions