CompletionStage是否总是在CompletionException中包装异常?

Gil*_*ili 16 java completable-future

CompletionStage的Javadoc指出:

[...]如果一个阶段的计算突然以(未经检查的)异常或错误终止,那么所有需要完成的依赖阶段也会异常完成,并且CompletionException将异常作为其原因.

看作异常完成总是包含异常,CompletionException为什么这样做exceptionally(),whenComplete()handle()代表异常Throwable代替CompletionException

这很重要,因为它可以防止人们直接在这些方法中重新抛出异常.

这些方法是否有可能接收除以外的异常CompletionException或者我可以安全地强制演员到这种类型吗?

(我在本地运行了一些测试,以及挖掘CompletableFuture源代码,乍一看,我没有看到如何抛出任何其他类型的异常.)

Sot*_*lis 9

这些方法是否有可能接收除以外的异常 CompletionException

是的,这是可能的,你不应该转换为CompletionException没有instanceof检查(或您的使用情况进行审查).

举个例子

CompletableFuture<Void> root = new CompletableFuture<>();
root.whenComplete((v, t) -> {
    System.out.println(t.getClass()); // class java.io.IOException
});
root.completeExceptionally(new IOException("blow it up"));
Run Code Online (Sandbox Code Playgroud)

whenComplete将收到IOException而不是CompletionException包装它.相同的行为适用于exceptionallyhandle.


阶段的计算在Javadoc中定义:

由阶段执行的计算可以表示为a Function, ConsumerRunnable(使用具有包括分别应用,接受或运行的名称的方法),这取决于它是否需要参数和/或产生结果.

我相信这句话

如果一个阶段的计算突然以(未经检查的)异常或错误终止

指的是由于抛出异常而突然终止的那些Function#apply,Consumer#accept或者Runnable#run方法之一,而不是因为某个阶段通过某种其他机制异常地完成.

另请注意,Javadoc说

此接口未定义最初创建,强制完成正常或异常,探测完成状态或结果或等待阶段完成的方法.实施CompletionStage可以酌情提供实现这种效果的手段

换句话说,该接口允许实现异常地完成阶段而不会突然终止任何计算.我认为这允许新的行为.


如果我们从以前扩展我的例子

CompletableFuture<Void> root = new CompletableFuture<>();
CompletableFuture<Void> child = root.whenComplete((v, t) -> {
    System.out.println(t.getClass()); // class java.io.Exception
});
child.whenComplete((v, t) -> {
    System.out.println(t.getClass()); // class java.util.concurrent.CompletionException
});
root.completeExceptionally(new IOException("blow it up"));
Run Code Online (Sandbox Code Playgroud)

到你会注意到附加完成child接收一个CompletionException包装原IOException.这不是明显,我从Javadoc中,其中规定

返回CompletionStage与此阶段具有相同结果或异常的new

总而言之,似乎a的原始例外情况completeExceptionally被传递给直接家属,而受抚养人的家属则收到一个附件CompletionException.