Java 8 CompletableFuture Handle Exception

Exception handling is important in software development, Java 8 CompletableFuture also provides methods to handle errors when they occurs.

Related article:
Java Future
Java 8 CompletableFuture
Java 8 Multiple CompletableFutures

I. Ways to handle exception

1. Using exceptionally method


CompletableFuture exceptionally()

For the example in previous post, we should use exceptionally() after chain of thenApply() methods:


future = future.thenApply(Integer::parseInt) // input String: "not detected"
				.thenApply(r -> r * 2 * Math.PI)
				.thenApply(s -> "apply>> " + s)
				.exceptionally(ex -> "Error: " + ex.getMessage());

Run the code, the result will be:


Error: java.lang.NumberFormatException: For input string: "not detected"

"not detected" is the String we return to future object before call the first thenApply() method.

2. Using handle method

Another way to handle exception is using handle method:

<U> CompletableFuture<U> handle()

In the example, instead of using exceptionally, we can make a more flexible code like this

future = future.thenApply(Integer::parseInt) // input String: "not detected"
		.thenApply(r -> r * 2 * Math.PI)
		.thenApply(s -> "apply>> " + s)
//				.exceptionally(ex -> "Error: " + ex.getMessage())
		.handle((result, ex) -> {
			if (result != null) {
				return result;
			} else {
				return "Error handling: " + ex.getMessage();
			}
		});

Run the code, the result will be:


accept: Error handling: java.lang.NumberFormatException: For input string: "not detected"

II. Source code

In the example, we pass 3 as input parameter to make an error when calling numbers.get(index). The future object then bring a String "not detected".
Exception will occur when invoking thenApply(Integer::parseInt). So we catch exception using exceptionally/handle method.

	package com.grokonez.completablefuture;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;

public class MainApp {

	private static ArrayList<String> numbers = new ArrayList<String>(Arrays.asList("0", "1", "2"));

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		System.out.println("Requesting");

		CompletableFuture<String> future = createCF(3);

		future = future.thenApply(Integer::parseInt)
				.thenApply(r -> r * 2 * Math.PI)
				.thenApply(s -> "apply>> " + s)
//				.exceptionally(ex -> "Error: " + ex.getMessage())
				.handle((result, ex) -> {
					if (result != null) {
						return result;
					} else {
						return "Error handling: " + ex.getMessage();
					}
				});

		// future.complete("foo");
		future.thenAccept(result -> System.out.println("accept: " + result));

		// other statements
		for (int i = 1; i <= 3; i++) {
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("running outside... " + i + " time");
		}

		// future.complete("foo");
		String contents = future.get();
		System.out.println("Future result: " + contents);
	}

	private static CompletableFuture<String> createCF(int index) {
		return CompletableFuture.supplyAsync(new Supplier<String>() {
			@Override
			public String get() {
				try {
					System.out.println("inside future: waiting for detecting...");
					for (int i = 1; i <= 5; i++) {
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println("running inside Future... " + i + " sec");
					}
					System.out.println("inside future: done...");

					return numbers.get(index);
				} catch (Throwable e) {
					return "not detected";
				}
			}
		});
	}
}

Check results in Console Screen:


Requesting
inside future: waiting for detecting...
running outside... 1 time
running inside Future... 1 sec
running outside... 2 time
running outside... 3 time
running inside Future... 2 sec
running inside Future... 3 sec
running inside Future... 4 sec
running inside Future... 5 sec
inside future: done...
accept: Error handling: java.lang.NumberFormatException: For input string: "not detected"
Future result: Error handling: java.lang.NumberFormatException: For input string: "not detected"


By grokonez | December 14, 2016.

Last updated on April 19, 2021.



Related Posts


5 thoughts on “Java 8 CompletableFuture Handle Exception”

  1. How to propagate a checked exception(Let’s say ManagerException) all the way to the API layer where I have return logic to convert this ManagerException and render to JSON. I have return special logic to convert it into JSON because in Play framework, whenever I throw RuntimeException it creates response in HTML form(which play renderers it through it custom handler).

    So my basic question is how to propogate exception to the API layer. I say this because when I throw Runtime exception from let’s say thenApplyAsync(), I am unable to catch this exception in my API layer.(The thrown exception just gets displayed in an ugly manner in Postman in HTML format

  2. Please provide the real time scenario by using CompletableFuture and Future.

    So we can able to understand the actual difference between CompletableFuture and Future.

  3. Thanks for the great post! Is there a way to conditionally handle exceptions, like so:

    future
    .thenCompose((Function<Response, CompletableFuture>) res -> {
               try {
                  Thread.sleep(params.delay.toMillis());
                   return CompleteableFuture.completedFuture(res);
                } catch (InterruptedException err) {
                  CompletableFuture errFut = new CompletableFuture();
                  errFut.completeExceptionally(err);
                  return errFut;
                }
            })
            .handle(((res, exception) -> {
              if (exception != null && isFatalException.apply(exception)) {
                CompletableFuture errFut = new CompletableFuture();
                errFut.completeExceptionally(exception);
                return errFut;
              }
              return CompletableFuture.completedFuture(res);
            }));
    

Got Something To Say:

Your email address will not be published. Required fields are marked *

*