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

时间:2018-03-12 08:34:07

标签: java completable-future

CompletionStage Javadoc声明:

  

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

看作异常完成总是在CompletionException中包含异常,为什么exceptionally()whenComplete()handle()将异常表示为Throwable而不是CompletionException }?

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

这些方法是否可以接收CompletionException以外的其他异常?或者我可以安全地强制转换为此类型吗?

(我在本地运行了一些测试,以及挖掘CompletableFuture源代码,乍一看,我看不出有什么其他类型的异常可以抛出。)

1 个答案:

答案 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包裹它。相同的行为适用于exceptionallyhandle

舞台的计算在Javadoc中定义:

  

阶段执行的计算可以表示为Function,   ConsumerRunnable(使用名称包含apply的方法,   分别接受或运行,具体取决于是否需要   参数和/或产生结果。

我相信这句话

  

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

指的是Function#applyConsumer#acceptRunnable#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