Liza Shakury
Liza Shakury

Reputation: 738

Throw the original (inner) exception within a function in CompletableFuture?

I am new to Java, so I hope this is not trivial, but I really could not find what I am looking for.

I have a function that throws Exception:

public String foo(String s) throws MyException {
    if ("a".equals(s)){
      return s;
    } else {
      throw new MyException("Oh no!");
    }
}

When MyException is just:

class MyException extends Exception{

  String str1;

  MyException(String str2) {
    str1=str2;
  }
  public String toString(){
    return ("MyException Occurred: "+str1) ;
  }
}

Now I have another method that calls foo inside CompletableFuture:

private CompletableFuture<String> test() throws Exception{
        return CompletableFuture.supplyAsync(() -> foo("b"));
}

But foo throws exception, so there is a compilation error here since the call for foo is unhandled exception.

All I want is to throw the original(inner) exception. How can I do that?

Upvotes: 1

Views: 1361

Answers (3)

Joop Eggen
Joop Eggen

Reputation: 109613

  1. The method foo must not throw a checked exception, but a not-declarable RuntimeException.

    class MyException extends RuntimeException
    
  2. Creating a Future already does not execute the foo, will do that in another call. So cannot throw anything.

    private static CompletableFuture<String> test() {
        return CompletableFuture.supplyAsync(() -> foo("b"));
    }
    
  3. Completion can be waited upon by get() or get with timeout. This will pass the thrown MyException by wrapping it as cause of an ExecutionException.

    try { test().get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.getCause().printStackTrace(); }

  4. Not to forget intercepting the exception with exceptionally:

    try {
        String s = test().exceptionally(throwable -> {
           throwable.getCause().printStackTrace();
           return "xxx"; }).get();
        System.err.println("s=" + s);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    

Upvotes: 2

František Hartman
František Hartman

Reputation: 15086

There are two issues you have.

  1. You cannot throw checked exceptions inside lambda expressions, see e.g. this answer. To handle this you can either use catch block inside the lambda expression or use runtime exception.

  2. The supplyAsync(() -> foo("b")) means it will run asynchronously in another thread at some later point, e.g. when you call .get() on the result. So it doesn't make sense for the test() method to throw the exception.

Upvotes: 4

Krzysztof Cichocki
Krzysztof Cichocki

Reputation: 6412

You need to serve this checked MyException exception inside the implementation of the CompletableFuture because it is "checked exception" meaning it is dervied from Exception class. Either serve it or change the MyException to be extended from RuntimeException, then you don't need to serve it (catch it).

Upvotes: 1

Related Questions