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
Throwing exception from CompletableFuture
提问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 CompletionException
anyway, 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 Supplier
will get wrapped into a CompletionException
when calling join
, except the ServerException
we have already wrapped in a CompletionException
.
所有在异步处理中抛出的异常在调用时Supplier
都会被包装到 a 中,除了我们已经包装在 a 中。CompletionException
join
ServerException
CompletionException
When we re-throw the cause of the CompletionException
, we may face unchecked exceptions, i.e. subclasses of Error
or 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 ServerException
in its original form passed via the exception
future. Note that we have to ensure that a
has been completed (like calling join()
first), before we query the exception
future, to avoid race conditions.
此解决方案将以包装形式重新抛出所有“意外”的可抛出对象,但仅以ServerException
通过exception
未来传递的原始形式抛出自定义。请注意,在我们查询未来之前,我们必须确保a
已完成(例如join()
先调用)exception
,以避免竞争条件。
回答by Eugene
I think that you should wrap that into a RuntimeException
and 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 unwrap
that..
然后你可以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 CompletableFuture
in 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 CompletableFuture
in 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 handle
method- 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 exceptionally
Method- similar to handle
but 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 whenComplete
Method- 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;
}