Java 从 CompletableFuture 抛出异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44409962/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:32:06  来源:igfitidea点击:

Throwing exception from CompletableFuture

javaexceptionexception-handlingjava-8completable-future

提问by ayushgp

I have the following code:

我有以下代码:

// 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()throws a ServerException. I don't want to handle this here but throw the exception from someFunc()to caller of myFunc().

someFunc()抛出一个ServerException. 我不想在这里处理这个问题,但是从抛出异常someFunc()给呼叫者myFunc()

采纳答案by Holger

Your code suggests that you are using the result of the asynchronous operation later in the same method, so you'll have to deal with CompletionExceptionanyway, so one way to deal with it, is

您的代码表明您稍后在同一方法中使用异步操作的结果,因此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
}

All exceptions thrown inside the asynchronous processing of the Supplierwill get wrapped into a CompletionExceptionwhen calling join, except the ServerExceptionwe have already wrapped in a CompletionException.

所有在异步处理中抛出的异常在调用时Supplier都会被包装到 a 中,除了我们已经包装在 a 中。CompletionExceptionjoinServerExceptionCompletionException

When we re-throw the cause of the CompletionException, we may face unchecked exceptions, i.e. subclasses of Erroror RuntimeException, or our custom checked exception ServerException. The code above handles all of them with a multi-catch which will re-throw them. Since the declared return type of getCause()is Throwable, the compiler requires us to handle that type despite we already handled all possible types. The straight-forward solution is to throw this actually impossible throwable wrapped in an AssertionError.

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

Alternatively, we could use an alternative result future for our custom exception:

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

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
}

This solution will re-throw all “unexpected” throwables in their wrapped form, but only throw the custom ServerExceptionin its original form passed via the exceptionfuture. Note that we have to ensure that ahas been completed (like calling join()first), before we query the exceptionfuture, to avoid race conditions.

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

回答by Eugene

I think that you should wrap that into a RuntimeExceptionand throw that:

我认为你应该把它包装成 aRuntimeException并抛出:

 throw new RuntimeException(ex);

Or many be a small utility would help:

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

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();
}

And then you could unwrapthat..

然后你可以unwrap那样..

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

回答by holi-java

Even if other's answer is very nice. but I give you another way to throw a checked exception in CompletableFuture.

即使别人的回答很好。但我给你另一种在CompletableFuture.

IFyou don't want to invoke a CompletableFuturein another thread, you can use an anonymous class to handle it like this:

如果您不想CompletableFuture在另一个线程中调用 a ,您可以使用匿名类来处理它,如下所示:

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

IFyou want to invoke a CompletableFuturein another thread, you also can use an anonymous class to handle it, but run method by runAsync:

如果您想CompletableFuture在另一个线程中调用 a ,您也可以使用匿名类来处理它,但通过runAsync以下方式运行方法:

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

回答by mel3kings

For those looking for other ways on exception handling with completableFuture

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

Below are several ways for example handling Parsing Error to Integer:

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

1. Using handlemethod- which enables you to provide a default value on exception

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. Using exceptionallyMethod- similar to handlebut less verbose

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. Using whenCompleteMethod- using this will stop the method on its tracks and not execute the next thenAcceptAsync

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. Propagating the exception via completeExceptionally

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;
    }