[concurrency-interest] Exception handling with CompletionStage

Pavel Rappo pavel.rappo at gmail.com
Wed Jan 17 15:28:21 EST 2018


Hello,

I have a question regarding a case I ran into while handling an exception
relayed through a sequence of stages. Consider the following scenarios:

1.

    public static void main(String[] args) {
        CompletableFuture.failedFuture(new RuntimeException("hello")).join();
    }

-- stdout --
Exception in thread "main" java.util.concurrent.CompletionException:
java.lang.RuntimeException: hello
   at java.base/java.util.concurrent.CompletableFuture.reportJoin(CompletableFuture.java:412)
   at java.base/java.util.concurrent.CompletableFuture.join(CompletableFuture.java:2044)
   at CF.main(CF.java:6)
Caused by: java.lang.RuntimeException: hello
   ... 1 more

2.

    public static void main(String[] args) {
        CompletableFuture.failedFuture(new RuntimeException("hello"))
                .whenComplete((r, e) -> System.out.println("Error: " + e))
                .join();
    }

-- stdout --

Error: java.lang.RuntimeException: hello
Exception in thread "main" java.util.concurrent.CompletionException:
java.lang.RuntimeException: hello
   at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:331)
   at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:346)
   at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:870)
   at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:883)
   at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2251)
   at CF.main(CF.java:7)
Caused by: java.lang.RuntimeException: hello
   at CF.main(CF.java:6)

3.

    public static void main(String[] args) {
        CompletableFuture.failedFuture(new RuntimeException("hello"))
                .whenComplete((r, e) -> System.out.println("Error 1: " + e))
                .whenComplete((r, e) -> System.out.println("Error 2: " + e))
                .join();
    }

-- stdout --

Error 1: java.lang.RuntimeException: hello
Error 2: java.util.concurrent.CompletionException:
java.lang.RuntimeException: hello
Exception in thread "main" java.util.concurrent.CompletionException:
java.lang.RuntimeException: hello
   at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:331)
   at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:346)
   at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:870)
   at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:883)
   at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2251)
   at CF.main(CF.java:7)
Caused by: java.lang.RuntimeException: hello
   at CF.main(CF.java:6)

-------------

I guess the difference in these behaviors could be (somewhat) explained by this
passage in the javadoc for CompletionStage:

 * In all other cases, if a stage's computation terminates abruptly
 * with an (unchecked) exception or error, then all dependent stages
 * requiring its completion complete exceptionally as well, with a
 * {@link CompletionException} holding the exception as its cause.

What was the rationale behind passing a wrapped exception to the dependant
stage? Why is it not wrapped in the first place (in the failedFuture method)?

And finally. How would one organise exception handling not being sure if the
target exception is wrapped or not?

Thanks,
-Pavel


More information about the Concurrency-interest mailing list