简体   繁体   English

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

[英]How to throw a custom exception from CompletableFuture?

Question: how can I directly throw a custom exception from .exceptionally() ? 问题:如何直接从.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());
}

Problem: I just always get a CompletionException whose ex.getCause() is instanceof BadRequestException . 问题:我总是得到一个CompletionExceptionex.getCause()BadRequestException instanceof。

Is that possible at all? 这有可能吗?

As said by Didier L , exceptions thrown by the functions (or generally exceptions that completed a CompletableFuture ) are always wrapped in a CompletionException (unless they are already a CompletionException or CancellationException ). 正如Didier L所说,函数抛出的异常(或者通常是完成 CompletableFuture 异常 )总是包含在CompletionException (除非它们已经是CompletionExceptionCancellationException )。

But note that your code becomes much simpler when not even trying to translate the exception via exceptionally : 但请注意,甚至在尝试通过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;
}

or 要么

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

Since exceptionally 's primary purpose is translating an exception to a non-exceptional result value, using it for translating the exception to another thrown exception was not the best fit anyway and it also needed an instanceof . 由于exceptionally的主要目的是将异常转换为非异常结果值,因此使用它将异常转换为另一个抛出的异常并不是最合适的,它还需要一个instanceof So performing this translation in the catch clause saves you from another translation step. 因此,在catch子句中执行此转换将使您免于另一个转换步骤。

This is not possible. 这是不可能的。 The Javadoc of join() clearly states: join()Javadoc明确指出:

Returns the result value when complete, or throws an (unchecked) exception if completed exceptionally. 完成后返回结果值,如果异常完成则抛出(未经检查的)异常。 To better conform with the use of common functional forms, if a computation involved in the completion of this CompletableFuture threw an exception, this method throws an (unchecked) CompletionException with the underlying exception as its cause. 为了更好地符合常用函数形式的使用, 如果完成此CompletableFuture所涉及的计算引发异常,则此方法将抛出(未经检查的) CompletionException ,并将基础异常作为其原因。

(emphasis is mine) (重点是我的)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM