令人惊讶的Java 8 CompletableFuture行为异常方法

Luk*_*kas 33 exception java-8 completable-future

我遇到过Java 8 CompletableFuture.exceptionally方法的奇怪行为.如果我执行此代码,它可以正常工作并打印java.lang.RuntimeException

CompletableFuture<String> future = new CompletableFuture<>();

future.completeExceptionally(new RuntimeException());

future.exceptionally(e -> {
            System.out.println(e.getClass());
            return null;
});
Run Code Online (Sandbox Code Playgroud)

但是如果我在将来的处理中添加另一个步骤,就像thenApply异常类型更改为java.util.concurrent.CompletionException包含在内部的原始异常.

CompletableFuture<String> future = new CompletableFuture<>();

future.completeExceptionally(new RuntimeException());

future.thenApply(v-> v).exceptionally(e -> {
            System.out.println(e);
            return null;
});
Run Code Online (Sandbox Code Playgroud)

有什么理由说这应该发生吗?在我看来,这是非常令人惊讶的.

Hol*_*ger 31

此行为CompletionStage(第四个项目符号)的类文档中指定:

方法handle另外允许阶段计算替换结果,该替换结果可以使得能够通过其他依赖阶段进一步处理.在所有其他情况下,如果一个阶段的计算突然以(未经检查的)异常或错误终止,那么所有需要完成的依赖阶段也会异常完成,CompletionException并将异常作为其原因.

如果你认为你可能知道你所调用的阶段是否exceptionally失败,或者其中一个是直接或间接的先决条件,那就不足为奇了.


Gag*_*lra 7

是的,行为是预期的,但如果你想要从前一个阶段抛出的原始异常,你可以简单地使用这个 -

CompletableFuture<String> future = new CompletableFuture<>();

future.completeExceptionally(new RuntimeException());

future.thenApply(v-> v).exceptionally(e -> {
        System.out.println(e.getCause()); // returns a throwable back
        return null;
});
Run Code Online (Sandbox Code Playgroud)