在 Java 中处理 CompletableFuture 错误的方法
Ways to handle error in CompletableFuture in Java
我在使用 CompletableFuture
时遇到了以下用例:
public void someFunction () {
CompletableFuture.runAsync(() -> computations())
.exceptionally((err) -> {
log.info(err + "");
return null;
});
}
public void computations() {
list.stream.forEach(() -> otherFunction());
}
public void otherFunction() {
//computations which can throw some error
}
正如你在这里看到的,我可以很容易地 log
exceptionally
块中的错误但是如果我不希望我的程序停止并继续直到 [=15 的所有元素=] 被迭代。如果有任何错误,我想记录下来并继续下一步而不是停止应用程序。
可以尝试catch抛出Exception的代码如下:不阻塞forEach循环直接对每个item进行异常处理
public void otherFunction() {
try {
//computations which can throw some error
} catch (Exception e) {
// Log and handle error without blocking analysis for following items
}
}
如果您已经知道 otherFunction 可以抛出什么异常,您可以显式地只捕获该异常并将异常留作系统处理其他异常。
如果你想缓存确切的异常并在以后处理它,你也可以这样做(注意这只会抛出列表迭代抛出的最后一个异常):
public void someFunction () {
CompletableFuture.runAsync(() -> {
try {
computations();
} catch (Exception e) {
e.printStackTrace();
}
});
}
public void computations() throws Exception {
AtomicReference<Exception> exception = new AtomicReference<>();
list.forEach(() -> {
try {
otherFunction();
} catch (Exception e) {
exception.set(e);
}
});
if (exception.get() != null)
throw exception.get();
}
public void otherFunction() throws Exception {
throw new Exception();
}
或者如果你想缓存所有异常:
public void someFunction () {
CompletableFuture.runAsync(() -> {
List<Exception> exceptions = computations();
exceptions.forEach(Throwable::printStackTrace);
});
}
public List<Exception> computations() {
final List<Exception> exceptions = new ArrayList<>();
list.forEach(() -> {
try {
otherFunction();
} catch (Exception e) {
exceptions.add(e);
}
});
return exceptions;
}
public void otherFunction() throws Exception {
throw new Exception();
}
在使用 CompletableFuture 编写代码时,异常处理起着重要的作用。 IncompleteFuture 提供了三种方法来处理它们:handle()、whenComplete() 和 exceptionally()。如果您没有使用 API 的经验,您很容易迷路,因为它们看起来很相似。以下部分解释了它们之间的差异,并帮助您确定最适合您情况的选项。我的目标是详细描述每个 API,然后比较它们的用法,最后提供一些每个 API 最有用的示例。虽然是Java11写的,但是Java8里面的概念应该还是比较熟悉的,开始吧。
句柄:
通过将当前完整未来的结果和异常传递给方法 handle(),您可以将当前结果转换为另一个结果或检索异常。
给定“Oops”作为异常,我们可以使用 handle() 来处理结果和异常,从异常中恢复或直接 returning 消息。
结果在exceptionally() 方法中不可用。您可以访问异常。由于该方法是专门为处理异常而命名的,因此该方法仅用于处理这些情况。如果成功实现可完成的未来,将跳过“例外”中的逻辑。
当一个失败的 future return 是一个异常“Oops”时,我们可以利用 exceptionally 从失败中恢复。
此结果将包含在完整的未来 cf1:
下一个例子展示了命令在执行过程中是如何被跳过的。未来 return 成功时就可以了。添加另一个处理异常的阶段时,不会执行该逻辑。如果完整的未来是 CF1,它将只是 return 与 CF0 相同的值。
我在使用 CompletableFuture
时遇到了以下用例:
public void someFunction () {
CompletableFuture.runAsync(() -> computations())
.exceptionally((err) -> {
log.info(err + "");
return null;
});
}
public void computations() {
list.stream.forEach(() -> otherFunction());
}
public void otherFunction() {
//computations which can throw some error
}
正如你在这里看到的,我可以很容易地 log
exceptionally
块中的错误但是如果我不希望我的程序停止并继续直到 [=15 的所有元素=] 被迭代。如果有任何错误,我想记录下来并继续下一步而不是停止应用程序。
可以尝试catch抛出Exception的代码如下:不阻塞forEach循环直接对每个item进行异常处理
public void otherFunction() {
try {
//computations which can throw some error
} catch (Exception e) {
// Log and handle error without blocking analysis for following items
}
}
如果您已经知道 otherFunction 可以抛出什么异常,您可以显式地只捕获该异常并将异常留作系统处理其他异常。
如果你想缓存确切的异常并在以后处理它,你也可以这样做(注意这只会抛出列表迭代抛出的最后一个异常):
public void someFunction () {
CompletableFuture.runAsync(() -> {
try {
computations();
} catch (Exception e) {
e.printStackTrace();
}
});
}
public void computations() throws Exception {
AtomicReference<Exception> exception = new AtomicReference<>();
list.forEach(() -> {
try {
otherFunction();
} catch (Exception e) {
exception.set(e);
}
});
if (exception.get() != null)
throw exception.get();
}
public void otherFunction() throws Exception {
throw new Exception();
}
或者如果你想缓存所有异常:
public void someFunction () {
CompletableFuture.runAsync(() -> {
List<Exception> exceptions = computations();
exceptions.forEach(Throwable::printStackTrace);
});
}
public List<Exception> computations() {
final List<Exception> exceptions = new ArrayList<>();
list.forEach(() -> {
try {
otherFunction();
} catch (Exception e) {
exceptions.add(e);
}
});
return exceptions;
}
public void otherFunction() throws Exception {
throw new Exception();
}
在使用 CompletableFuture 编写代码时,异常处理起着重要的作用。 IncompleteFuture 提供了三种方法来处理它们:handle()、whenComplete() 和 exceptionally()。如果您没有使用 API 的经验,您很容易迷路,因为它们看起来很相似。以下部分解释了它们之间的差异,并帮助您确定最适合您情况的选项。我的目标是详细描述每个 API,然后比较它们的用法,最后提供一些每个 API 最有用的示例。虽然是Java11写的,但是Java8里面的概念应该还是比较熟悉的,开始吧。
句柄: 通过将当前完整未来的结果和异常传递给方法 handle(),您可以将当前结果转换为另一个结果或检索异常。 给定“Oops”作为异常,我们可以使用 handle() 来处理结果和异常,从异常中恢复或直接 returning 消息。
结果在exceptionally() 方法中不可用。您可以访问异常。由于该方法是专门为处理异常而命名的,因此该方法仅用于处理这些情况。如果成功实现可完成的未来,将跳过“例外”中的逻辑。 当一个失败的 future return 是一个异常“Oops”时,我们可以利用 exceptionally 从失败中恢复。
此结果将包含在完整的未来 cf1:
下一个例子展示了命令在执行过程中是如何被跳过的。未来 return 成功时就可以了。添加另一个处理异常的阶段时,不会执行该逻辑。如果完整的未来是 CF1,它将只是 return 与 CF0 相同的值。