CompletionStage Javadoc声明:
[...]如果一个阶段的计算突然以(未经检查的)异常或错误终止,那么所有需要完成的依赖阶段也会异常完成,并且CompletionException将异常作为其原因。
看作异常完成总是在CompletionException
中包含异常,为什么exceptionally()
,whenComplete()
和handle()
将异常表示为Throwable
而不是CompletionException
}?
这很重要,因为它可以防止人们直接在这些方法中重新抛出异常。
这些方法是否可以接收CompletionException
以外的其他异常?或者我可以安全地强制转换为此类型吗?
(我在本地运行了一些测试,以及挖掘CompletableFuture源代码,乍一看,我看不出有什么其他类型的异常可以抛出。)
答案 0 :(得分:6)
这些方法是否有可能接收除以外的异常
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"));
whenComplete
将收到IOException
而不是CompletionException
包裹它。相同的行为适用于exceptionally
和handle
。
舞台的计算在Javadoc中定义:
阶段执行的计算可以表示为
Function
,Consumer
或Runnable
(使用名称包含apply的方法, 分别接受或运行,具体取决于是否需要 参数和/或产生结果。
我相信这句话
如果一个阶段的计算突然终止(未经检查) 异常或错误
指的是Function#apply
,Consumer#accept
或Runnable#run
方法之一由于thrown exception而突然终止,而不是因为某个阶段通过某种其他机制异常完成。
另请注意,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"));
您会注意到child
附带的完成情况会收到包裹原始CompletionException
的{{1}}。 Javadoc表示
返回带有相同结果或例外的新
IOException
这个阶段
总而言之,似乎来自CompletionStage
的原始异常传递给直接家属,而受抚养人的家属会收到一个封闭的completeExceptionally
。