从completeablefuture引发实际异常



我正在使用如下的completablefuture进行并行调用,

public Response getResponse() {
Response resultClass = new Response();
try {
CompletableFuture<Optional<ClassA>> classAFuture
= CompletableFuture.supplyAsync(() -> service.getClassA() );
CompletableFuture<ClassB> classBFuture
= CompletableFuture.supplyAsync(() -> {
try {
return service.getClassB(); 
}
catch (Exception e) {
throw new CompletionException(e);
}
});
CompletableFuture<Response> responseFuture =
CompletableFuture.allOf(classAFuture, classBFuture)
.thenApplyAsync(dummy -> {
if (classAFuture.join().isPresent() {
ClassA classA = classAFuture.join();
classA.setClassB(classBFuture.join());
response.setClassA(classA)
}
return response;
});
responseFuture.join();
} catch (CompletionExecution e) {
throw e;
}
return response;
}

我需要为return service.getClassB()添加try-catch,因为它在方法getClassB中抛出异常。

现在我面临的问题是,如果service.getClassB()抛出错误,它总是被包裹在java.util.concurrent.ExecutionException中。在这种情况下,该方法抛出UserNameNotFoundException,但它被封装在ExecutionException中,并且没有在@ControllerAdvice异常处理程序类的正确位置捕获。我尝试了不同的选择使用一次性,但没有帮助。

有没有一种好的方法来处理异常并打开包装并将其发送到@ControllerAdvice类?

您的代码有几个错误,比如引用了一个未在此代码中声明的变量response,很可能是开头声明的resultClass
ClassA classA = classAFuture.join();行突然忽略了这个future封装了一个Optional,并且缺少);分隔符。

此外,当有一个干净的替代方案时,应该避免从周围的代码中访问变量。此外,使用allOf组合两个期货是不必要的复杂操作。

如果我正确理解你的意图,你想做一些类似的事情

public Response getResponse() {
return CompletableFuture.supplyAsync(() -> service.getClassA())
.thenCombine(CompletableFuture.supplyAsync(() -> {
try {
return service.getClassB();
}
catch(ExecutionException e) {
throw new CompletionException(e.getCause());
}
}), (optA, b) -> {
Response response = new Response();
optA.ifPresent(a -> {
a.setClassB(b);
response.setClassA(a);
});
return response;
})
.join();
}

解决所描述问题的关键点是捕获最特定的异常类型。当您捕获ExecutionException时,您知道它将包装实际的异常,并且可以无条件地提取它。当getClassB()声明您必须捕获的其他已检查异常时,添加另一个catch子句,但要特定,而不是捕获Exception,例如

try {
return service.getClassB();
}
catch(ExecutionException e) {
throw new CompletionException(e.getCause());
}
catch(IOException | SQLException e) { // all of getClassB()’s declared exceptions
throw new CompletionException(e); //     except ExecutionException, of course
}

最新更新