我有以下代码:
// 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()
的调用者。
答案 0 :(得分:29)
您的代码建议您稍后在同一方法中使用异步操作的结果,因此您无论如何都必须处理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
}
Supplier
的异步处理中抛出的所有异常都会在调用CompletionException
时被包含在join
中,除了ServerException
我们已经包含在CompletionException
中1}}。
当我们重新抛出CompletionException
的原因时,我们可能会遇到未经检查的异常,即Error
或RuntimeException
的子类,或我们的自定义检查异常ServerException
。上面的代码使用multi-catch处理所有这些代码,这将重新抛出它们。由于声明的返回类型getCause()
是Throwable
,编译器要求我们处理该类型,尽管我们已经处理了所有可能的类型。直接的解决方案是将这个实际上不可能的throwable包裹在AssertionError
。
或者,我们可以为自定义异常使用替代结果:
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,但只会将自定义ServerException
以其exception
未来传递的原始形式抛出。请注意,在查询a
未来之前,我们必须确保join()
已完成(例如先调用exception
),以避免竞争条件。
答案 1 :(得分:11)
对于那些寻求通过completableFuture处理异常的其他方式的人
以下是处理解析为整数的错误的几种方法:
1。使用File(...)
方法-通过该方法,您可以提供有关异常的默认值
FileRepositoryBuilder builder = new FileRepositoryBuilder();
String gitPath = "\path\to\your\git\folder";
Repository repository = builder.setGitDir(new File(gitPath))
.readEnvironment().findGitDir().build();
listRepositoryContents(repository);
repository.close();
2。使用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);
});
类似,但较不详细
exceptionally
3。使用handle
方法-使用此方法将停止该方法的执行,而不会执行下一个CompletableFuture parser = CompletableFuture.supplyAsync(() -> "1")
.thenApply(Integer::parseInt)
.exceptionally(t -> {
t.printStackTrace();
return 0;
}).thenAcceptAsync(s -> System.out.println("CORRECT value: " + s));
whenComplete
4。通过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);
});
答案 2 :(得分:3)
我认为你应该把它包装成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();
}
答案 3 :(得分:1)
即使其他人的答案非常好。但是我给你另一种方法在CompletableFuture
中抛出一个检查过的异常。
IF 您不想在另一个帖子中调用CompletableFuture
,您可以使用匿名类来处理它:
CompletableFuture<A> a = new CompletableFuture<A>() {{
try {
complete(someObj.someFunc());
} catch (ServerException ex) {
completeExceptionally(ex);
}
}};
IF 你想在另一个线程中调用CompletableFuture
,你也可以使用匿名类来处理它,但是按runAsync
运行方法:
CompletableFuture<A> a = new CompletableFuture<A>() {{
CompletableFuture.runAsync(() -> {
try {
complete(someObj.someFunc());
} catch (ServerException ex) {
completeExceptionally(ex);
}
});
}};