如何从CompletableFuture抛出自定义异常?

时间:2018-02-28 13:08:32

标签: java java-stream completable-future

问题:如何直接从.exceptionally()投出自定义异常?

List<CompletableFuture<Object>> futures =
    tasks.stream()
        .map(task -> CompletableFuture.supplyAsync(() -> businessLogic(task))
        .exceptionally(ex -> {
                if (ex instanceof BusinessException) return null;

                //TODO how to throw a custom exception here??
                throw new BadRequestException("at least one async task had an exception");
        }))
        .collect(Collectors.toList());

try {
    List<Object> results = futures.stream()
        .map(CompletableFuture::join)
        .collect(Collectors.toList());
} catch (CompletionException e) {
        if (e.getCause() instanceof RuntimeException) {
              throw (RuntimeException) e.getCause();
        }
        throw new RuntimeException(e.getCause());
}

问题:我总是得到CompletionException ex.getCause()BadRequestException的实例。

这可能吗?

2 个答案:

答案 0 :(得分:4)

作为said by Didier L,函数抛出的异常(或通常exceptions that completedCompletableFuture)始终包含在CompletionException中(除非它们已经是CompletionException }或CancellationException)。

但请注意,即使尝试通过exceptionally转换异常,您的代码也会变得更加简单:

List<CompletableFuture<Object>> futures =
    tasks.stream()
        .map(task -> CompletableFuture.supplyAsync(() -> businessLogic(task)))
        .collect(Collectors.toList());
try {
    List<Object> results = futures.stream()
        .map(CompletableFuture::join)
        .collect(Collectors.toList());
} catch (CompletionException e) {
    throw e.getCause() instanceof BusinessException?
        new BadRequestException("at least one async task had an exception"): e;
}

… catch (CompletionException e) {
    throw e.getCause() instanceof BusinessException?
        new BadRequestException("at least one async task had an exception"):
        e.getCause() instanceof BusinessException? (RuntimeException)e.getCause(): e;
}

由于exceptionally的主要目的是将异常转换为非异常结果值,因此使用它将异常转换为另一个抛出异常并不是最合适的,它还需要{{1} }。因此,在instanceof子句中执行此转换将使您免于另一个转换步骤。

答案 1 :(得分:2)

这是不可能的。 Javadoc of join()明确指出:

  

完成后返回结果值,或抛出(未选中)   如果异常完成,则例外。为了更好地符合使用   常见的函数形式,如果计算涉及到   完成此CompletableFuture引发了一个例外,这种方法   向底层投掷(未经检查)CompletionException   例外是其原因。

(重点是我的)