在 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 相同的值。