从CompletableFuture引发异常

我有以下代码:

// 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()抛出一个 .我不想在这里处理这个问题,而是将异常从抛给的调用方。ServerExceptionsomeFunc()myFunc()


答案 1

您的代码表明您正在稍后在同一方法中使用异步操作的结果,因此无论如何您都必须处理,因此处理它的一种方法是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
}

在异步处理中抛出的所有异常都将被包装到一个 when 调用中,除了我们已经包装在 .SupplierCompletionExceptionjoinServerExceptionCompletionException

当我们重新抛出 的原因时,我们可能会遇到未经检查的异常,即 或 的子类,或者我们的自定义检查异常。上面的代码使用多重捕获来处理所有这些,这将重新抛出它们。由于声明的返回类型是 ,编译器要求我们处理该类型,尽管我们已经处理了所有可能的类型。直截了当的解决方案是将这个实际上不可能的可投掷物包裹在.CompletionExceptionErrorRuntimeExceptionServerExceptiongetCause()ThrowableAssertionError

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

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
}

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


答案 2

对于那些寻找其他方法处理异常与可兼容的未来

以下是几种处理将错误解析为整数的方法:

1. 使用句柄方法 - 使您能够在异常时提供默认值

CompletableFuture correctHandler = CompletableFuture.supplyAsync(() -> "A")
            .thenApply(Integer::parseInt)
            .handle((result, ex) -> {
                if (null != ex) {
                    ex.printStackTrace();
                    return 0;
                } else {
                    System.out.println("HANDLING " + result);
                    return result;
                }
            })
            .thenAcceptAsync(s -> {
                System.out.println("CORRECT: " + s);
            });

2.使用特殊方法 - 类似于但不那么冗长handle

CompletableFuture parser = CompletableFuture.supplyAsync(() -> "1")
                .thenApply(Integer::parseInt)
                .exceptionally(t -> {
                    t.printStackTrace();
                    return 0;
                }).thenAcceptAsync(s -> System.out.println("CORRECT value: " + s));

3. 使用 whenComplete 方法 - 使用此方法将停止该方法的轨道,并且不会执行下一个thenAcceptAsync

CompletableFuture correctHandler2 = CompletableFuture.supplyAsync(() -> "A")
                .thenApply(Integer::parseInt)
                .whenComplete((result, ex) -> {
                    if (null != ex) {
                        ex.printStackTrace();
                    }
                })
                .thenAcceptAsync(s -> {
                    System.out.println("When Complete: " + s);
                });

4. 通过 completeExceptionly 传播异常

public static CompletableFuture<Integer> converter(String convertMe) {
        CompletableFuture<Integer> future = new CompletableFuture<>();
        try {
            future.complete(Integer.parseInt(convertMe));
        } catch (Exception ex) {
            future.completeExceptionally(ex);
        }
        return future;
    }

推荐