问题:如何直接从.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
的实例。
这可能吗?
答案 0 :(得分:4)
作为said by Didier L,函数抛出的异常(或通常exceptions that completed和CompletableFuture
)始终包含在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
例外是其原因。
(重点是我的)