当前位置: 首页 > 面试题库 >

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

寇靖
2023-03-14
问题内容

该CompletionStage的Javadoc状态:

[…]如果阶段的计算由于(未经检查的)异常或错误而突然终止,则所有需要完成该过程的从属阶段也会异常完成,并且CompletionException将异常作为其原因。

看到异常完成总是将异常包装在CompletionException为什么中exceptionally()whenComplete()并且handle()将异常表示为Throwable而不是CompletionException

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

这些方法是否可能收到除以外的其他异常CompletionException?还是我可以安全地强制使用这种类型的演员?

(我在本地运行了一些测试,并浏览了CompletableFuture源代码,乍看之下,我不知道如何抛出任何其他类型的异常。)


问题答案:

这些方法是否可能收到除以外的其他异常 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根据(使用名称,包括应用,接受或运行,分别方法)是否需要参数和/或产生的结果。

我相信这句话

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

指的是其中的一个Function#applyConsumer#acceptRunnable#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"));

您会注意到随附的完成文件会child收到CompletionException原始文件的包装IOException。从Javadoc来看,这对我来说并不明显

返回一个新的,CompletionStage具有与该阶段 相同的 结果或 异常

总而言之,似乎来自a的原始异常completeExceptionally被传递给直接的从属,而从属的从属却收到一个封闭的CompletionException



 类似资料:
  • 我有一个小的性能问题,当使用try-catch子句时,最好指定可以获得的确切异常,或者只使用exception它更好?例子: 或者如果你不介意什么样的例外: 因为我知道你可以使用不同的异常来触发不同的效果,但我只是要求性能。

  • 我刚才问了一个问题。 这是关于在虚拟图书馆管理条件下处理异常。帖子上的答案令人信服,我不应该选择例外。 但是我刚刚在这里读了一篇文章,它很好地说明了这一点,并坚持了对我之前问题的回答 只有在希望开发人员对问题采取纠正措施或记录日志以进行事后调试时,才应创建新的异常。 由于我们应该编写它们来帮助开发人员而不是用户,这是否意味着异常仅在开发人员将使用的库中占有一席之地?,如果代码未被其他开发人员使用,

  • 问题内容: 这样做,即ConcurrentHashMap(所有非retreival操作,等)需要在被包裹块?我知道所有这些操作都是线程安全的,因此这样做有真正的好处/需要吗?使用的唯一操作是和。 问题答案: 不,这样做会失去您的利益。您也可以使用with 或锁定整个表(这是在中包装操作时要执行的操作,因为隐含的监视器是整个对象实例。) 目的是通过允许在表上进行并发读/写而不锁定整个表来提高并发代码

  • 问题内容: 使用原生(ES6)Promise。我应该以错误拒绝: 还是我应该拒绝一个字符串: 浏览器行为有什么区别? 问题答案: 是的,绝对可以。字符串不是错误,通常当您遇到错误时,这意味着出了点问题,这意味着您将真正享受良好的堆栈跟踪。没有错误-没有堆栈跟踪。 就像try / catch一样,如果您添加到抛出拒绝中,则希望能够记录堆栈跟踪,而抛出字符串会为您带来麻烦。 我在移动设备上,因此答案很

  • 问题内容: 在其中引发异常是否被认为是不好的形式?如果是这样,那么当某些类变量初始化为错误类型或类型错误时,可以接受的引发错误的方法是什么? 问题答案: 在内部引发异常是绝对可以的。在构造函数中没有其他好的方法来指示错误情况,并且标准库中有数百个示例,在这些示例中构建对象会引发异常。 当然,要提高的错误级别取决于您。如果向构造函数传递了无效的参数,则最好。

  • 问题内容: 我在Java中有这个工厂方法: 我想将两个已检查的异常转换为未检查的异常。最好的方法是什么? 我是否应该仅捕获异常并使用捕获的异常作为内部异常抛出新的RuntimeException? 有没有更好的方法可以做到这一点?或者我应该首先尝试这样做吗? 编辑: 只是为了澄清。这些异常将是致命的,因为配置文件实质上是程序的运行,所有异常都将在程序的顶层捕获并记录。 我的目的是避免不必要的引发异