从 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
的原因时,我们可能会面临未经检查的异常,即 Error
或 RuntimeException
的子类,或者我们自定义的检查异常 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;
}
我有以下代码:
// 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
的原因时,我们可能会面临未经检查的异常,即 Error
或 RuntimeException
的子类,或者我们自定义的检查异常 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;
}