从CompletableFuture exceptionally子句中抛出异常

时间:2018-04-13 17:53:35

标签: java

我在处理来自CompletableFuture方法的异常抛出时遇到问题。我认为应该可以从CompletableFuture的异常条款中抛出异常。例如,在下面的方法中,我预计executeWork将抛出RuntimeException,因为我在各个exceptionally子句中抛出一个,但是,这不起作用,我不知道为什么。< / p>

public void executeWork() {

  service.getAllWork().thenAccept(workList -> {
    for (String work: workList) {
      service.getWorkDetails(work)
        .thenAccept(a -> sendMessagetoQueue(work, a))
        .exceptionally(t -> {
          throw new RuntimeException("Error occurred looking up work details");
        });
  }
  }).exceptionally(t -> {
    throw new RuntimeException("Error occurred retrieving work list");
  });
}

1 个答案:

答案 0 :(得分:1)

您在这里做错了几件事(async programming is hard):

首先,正如@VGR指出的那样,当情况变坏时executeWork()不会引发异常-因为所有实际工作都是在另一个线程上完成的。 executeWork()实际上将立即返回-在安排了所有工作之后但没有完成任何工作。您可以在最后一个get()上调用CompletableFuture,这将等待工作完成或失败,并会引发任何相关异常。但这是强制同步,被认为是一种反模式。

第二,您不需要throw new RuntimeException()句柄中的exceptionally()-在您的情况下,实际上已调用了正确的错误(t)。

查看类似的同步代码,您的示例如下所示:

try {
  for (String work : service.getAllWork()) {
    try {
      var a = service.getWorkDetails(work);
      sendMessageToQueue(work, a);
    } catch (SomeException e) {
      throw new RuntimeException("Error occurred looking up work details");
    }
  }
} catch (SomeOtherException e) {
  throw new RuntimeException("Error occured retrieving work list");
}

因此,如您所见,捕获异常并抛出RuntimeException(也隐藏了真正的错误)并没有让异常传播到可以处理它们的地方,这没有任何好处。

exceptionally()步骤的目的是从异常中恢复-例如在从用户或IO检索数据失败或类似情况时放置默认值。示例:

service.getAllWork().thenApply(workList -> workList.stream()
    .map(work -> service.getWorkDetails(work)
        .thenAccept(a -> sendMessageToQueue(work, a)
        .exceptionally(e -> {
          reportWorkFailureToQueue(work, e);
          return null;
        })
     )
).thenCompose(futStream -> 
    CompletableFuture.allOf(futStream.toArray(CompletableFuture[]::new)))
.exceptionlly(e -> {
   // handle getAllWork() failures here, getWorkDetail/sendMessageToQueue
   // failures were resolved by the previous exceptionally and converted to null values
});