【问题标题】:Surprising behavior of Java 8 CompletableFuture exceptionally methodJava 8 CompletableFuture 异常方法的惊人行为
【发布时间】:2015-02-10 08:58:28
【问题描述】:

我遇到了 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;
});

但是如果我在以后的处理中添加另一个步骤,例如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;
});

有什么理由会发生这种情况吗?在我看来,这很令人惊讶。

【问题讨论】:

  • 查看 stackoverflow.com/q/49230980/14731 了解何时包装(或不包装)异常的概述。
  • 这是我发现的一篇文章,帮助我更好地理解了这个问题的解决方案 -> millross-consultants.com/…
  • @The0bserver,您添加的链接信息量很大,虽然不是全部,但我的很多疑问都清楚了:)
  • 很高兴我能帮上忙@NIGAGA。

标签: exception java-8 completable-future


【解决方案1】:

这种行为is specified in the class documentation of CompletionStage (fourth bullet)

方法handle 还允许该阶段计算替换结果,该结果可能允许其他相关阶段进行进一步处理。在所有其他情况下,如果某个阶段的计算因(未经检查的)异常或错误而突然终止,则所有需要其完成的相关阶段也会异常完成,CompletionException 将异常作为其原因。

如果您考虑到您可能知道您调用 exceptionally 的阶段是否失败,或者它的直接或间接先决条件之一是否失败,这并不奇怪。

【讨论】:

    【解决方案2】:

    是的,该行为是预期的,但如果您想要从先前阶段之一抛出的原始异常,您可以简单地使用它

    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;
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多