您的代码建议您稍后以相同的方法使用异步操作的结果,因此
CompletionException无论如何都必须进行处理,因此一种处理方法是
public void myFunc() throws ServerException { // Some pre CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> { try { return someObj.someFunc(); } catch(ServerException ex) { throw new CompletionException(ex); } }); // Some pre running in parallel to someFunc() A resultOfA; try { resultOfA = a.join(); } catch(CompletionException ex) { try { throw ex.getCause(); } catch(Error|RuntimeException|ServerException possible) { throw possible; } catch(Throwable impossible) { throw new AssertionError(impossible); } } // some pre using resultOfA}在的异步处理中抛出的所有异常
Supplier都将
CompletionException在调用时包装为一个
join,除了
ServerException我们已经包装在一个
CompletionException。
当重新引发的原因时
CompletionException,我们可能会遇到未检查的异常,即
Erroror的子类
RuntimeException或我们的自定义检查的异常
ServerException。上面的代码通过多次捕获来处理所有这些错误,然后将它们重新抛出。由于声明的返回类型
getCause()为
Throwable,尽管我们已经处理了所有可能的类型,但编译器仍要求我们处理该类型。直接的解决方案是将包裹在包装中的这个实际上不可能的可抛物抛出
AssertionError。
或者,我们可以为自定义异常使用将来的替代结果:
public void myFunc() throws ServerException { // Some pre CompletableFuture<ServerException> exception = new CompletableFuture<>(); CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> { try { return someObj.someFunc(); } catch(ServerException ex) { exception.complete(ex); throw new CompletionException(ex); } }); // Some pre running in parallel to someFunc() A resultOfA; try { resultOfA = a.join(); } catch(CompletionException ex) { if(exception.isDone()) throw exception.join(); throw ex; } // some pre using resultOfA}该解决方案将所有“意外”的可扔物以它们的包装形式重新抛出,但仅将自定义
ServerException以
exception将来通过的原始形式抛出。请注意,在查询未来之前,我们必须确保
a已完成操作(例如
join()先调用)
exception,以避免出现竞争情况。



