从 CompletableFuture 抛出异常

Throwing exception from 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() 抛出一个 ServerException。我不想在这里处理这个问题,而是将 someFunc() 的异常抛给 myFunc() 的调用者。

我认为你应该把它包装成一个 RuntimeException 然后扔掉它:

 throw new RuntimeException(ex);

或者许多是一个小实用程序会有所帮助:

static class Wrapper extends RuntimeException {

    private Wrapper(Throwable throwable) {
        super(throwable);
    }

    public static Wrapper wrap(Throwable throwable) {
        return new Wrapper(throwable);
    }

    public Throwable unwrap() {
        return getCause();
    }
}


 public static void go() {
    CompletableFuture<String> a = CompletableFuture.supplyAsync(() -> {
        try {
            throw new Exception("Just because");
        } catch (Exception ex) {
            throw Wrapper.wrap(ex);
        }
    });

    a.join();
}

然后你可以unwrap那个..

 try {
        go();
 } catch (Wrapper w) {
        throw w.unwrap();
 }

您的代码表明您稍后将在同一方法中使用异步操作的结果,因此无论如何您都必须处理 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() 的声明 return 类型是 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 未来传递的原始形式抛出自定义 ServerException。请注意,在我们查询 exception 未来之前,我们必须确保 a 已完成(例如先调用 join(),以避免竞争条件。

即使别人的回答很好。但我给你另一种方法在 CompletableFuture 中抛出检查异常。

IF 你不想在另一个线程中调用一个 CompletableFuture,你可以使用一个匿名的 class 来处理它:

CompletableFuture<A> a = new CompletableFuture<A>() {{
    try {
        complete(someObj.someFunc());
    } catch (ServerException ex) {
        completeExceptionally(ex);
    }
}};

IF你想在另一个线程中调用一个CompletableFuture,你也可以使用一个匿名的class来处理它,但是运行 方法 runAsync:

CompletableFuture<A> a = new CompletableFuture<A>() {{
    CompletableFuture.runAsync(() -> {
        try {
            complete(someObj.someFunc());
        } catch (ServerException ex) {
            completeExceptionally(ex);
        }
    });
}};

对于那些正在使用 completableFuture 寻找其他异常处理方法的人

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

1.使用 handle 方法 - 这使您能够在异常

时提供默认值
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。使用 exceptionally 方法 - 类似于 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.通过 completeExceptionally

传播异常
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;
    }