java - 从 CompletableFuture 抛出异常

标签 java exception exception-handling java-8 completable-future

我有以下代码:

// How to throw the ServerException?
public void myFunc() throws ServerException{
    // Some code
    CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
        try {
            return someObj.someFunc();
        } catch(ServerException ex) {
            // throw ex; gives an error here.
        }
    }));
    // Some code
}

someFunc() 抛出 ServerException。我不想在这里处理这个问题,而是将 someFunc() 的异常抛出给 myFunc() 的调用者。

最佳答案

您的代码表明您稍后在同一方法中使用异步操作的结果,因此无论如何您都必须处理 CompletionException,因此处理它的一种方法是

public void myFunc() throws ServerException {
    // Some code
    CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
        try { return someObj.someFunc(); }
        catch(ServerException ex) { throw new CompletionException(ex); }
    });
    // Some code 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 code using resultOfA
}

在调用 join 时,Supplier 的异步处理中抛出的所有异常都将被包装到 CompletionException 中,ServerException 除外 我们已经包裹在 CompletionException 中。

当我们重新抛出 CompletionException 的原因时,我们可能会遇到未经检查的异常,即 ErrorRuntimeException 的子类,或者我们的自定义检查异常 ServerException。上面的代码使用 multi-catch 处理所有这些,这将重新抛出它们。由于 getCause() 声明的返回类型是 Throwable,编译器要求我们处理该类型,尽管我们已经处理了所有可能的类型。直接的解决方案是将这个实际上不可能的 throwable 包裹在 AssertionError 中。

或者,我们可以为自定义异常使用替代结果 future:

public void myFunc() throws ServerException {
    // Some code
    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 code running in parallel to someFunc()

    A resultOfA;
    try {
        resultOfA = a.join();
    }
    catch(CompletionException ex) {
        if(exception.isDone()) throw exception.join();
        throw ex;
    }

    // some code using resultOfA
}

此解决方案将以包装形式重新抛出所有“意外”的 throwable,但仅以通过 exception future 传递的原始形式抛出自定义 ServerException。请注意,在查询 exception future 之前,我们必须确保 a 已经完成(例如先调用 join()),以避免竞争条件。

关于java - 从 CompletableFuture 抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44409962/

相关文章:

java - XSLT 性能注意事项

c# - 如果请求的实体在 Db 中不存在,我应该抛出哪个异常?

c# - 丢弃异常变量时是否存在技术差异?

php - 在多语言(例如英语和法语)应用程序中抛出异常

java - 将项目转换为分面形式后导入无法解决

java - MimeMessage 电子邮件不会发送附件

python - 如何处理从 except block 引发的异常链

.net - 当它们共享相同的类型时如何区分两个 .NET 异常?

用于过滤堆栈中引发的所有异常的 Ruby rack 中间件

java - RED5安装