在java8中的CompletableFuture中处理运行时异常

时间:2018-01-08 14:42:34

标签: exception java-8 completable-future

下面是我用来理解java8中completablefuture中的异常处理的示例代码。 如果我们按照文档使用特殊方法, 异常方法甚至捕获运行时异常并继续到管道中的最后一个块。

如果我们不使用特殊方法,那么就会打印出来并退出。

如果我的理解不正确,请纠正我。

问题是让我们说如果我想抛出运行时异常并希望应用程序停止。基本上如果我抛出Runtime异常,它就不应该进入下一个流水线块。我该怎么做任何指针都有帮助。

public static void main(String[] args) {
    final CompletableFuture<String> retrieveName = CompletableFuture.supplyAsync(() -> {
        System.out.println("running");
        int i = 0;
        if(i == 0) {
            throw new RuntimeException("ding");
        }
        return "test";
    }).exceptionally(it -> {
        System.out.println(it.getMessage());
        return "empty";
    }).thenApply(it -> {

        System.out.println("last block" + it);
        return "dummy";
    });
}

1 个答案:

答案 0 :(得分:2)

试试这个:

public static void main(String[] args) {
    try {
        final CompletableFuture<String> retrieveName = CompletableFuture.supplyAsync(() -> {
            System.out.println("running");
            int i = 0;
            if (i == 0) {
                throw new RuntimeException("ding");
            }
            return "test";
        }).exceptionally(it -> {
            if (it.getMessage().contains("ding")) {
                throw (RuntimeException) it;
            }
            System.out.println(it.getMessage());
            return "empty";
        }).thenApply(it -> {
            System.out.println("last block" + it);
            return "dummy";
        });
        retrieveName.join();
    } catch (Exception e) {
        System.out.println("main() exception, cause=" + e.getCause());
    }
}

这是输出:

  

运行

     

main()异常,cause = java.lang.RuntimeException:ding

我对您的代码进行了3次小改动:

  • 将它全部包裹在try-catch中
  • 例外()中为&#34; ding&#34;提出 RuntimeException 异常。
  • 添加了对 retrieveName.join()的调用。来自Javadoc的 CompletableFuture.join()
  

public T join()

     

完成时返回结果值,如果异常完成,会抛出(未经检查)异常

根据OP反馈进行更新-------&gt;

  

让我们说如果我想抛出运行时异常并希望应用程序   停。基本上如果我抛出Runtime异常,它就不应该继续   管道中的下一个区块。我该怎么办呢。

只需对代码进行2次更改,即可实现所需目标:

[1]完全删除 exceptionally()回调,以便CompletableFuture(CF)以异常终止。在OP代码的 exceptionally()中,异常被吞下而不是重新抛出,并返回CF,因此仍然执行 thenApply()方法。

[2]在main()的末尾添加对 retrieveName.join()的调用。这是一个阻塞调用,但由于该线程已终止,但异常与示例代码不相关。 join()方法将提取抛出的 RunTimeException 并重新抛出它,包含在 CompletionException 中。

以下是修改过的代码:

 public static void main(String[] args) {
    final CompletableFuture<String> retrieveName = CompletableFuture.supplyAsync(() -> {
        System.out.println("running");
        int i = 0;
        if(i == 0) {
            throw new RuntimeException("ding");
        }
        return "test";
    }).thenApply(it -> {
        System.out.println("last block" + it);
        return "dummy";
    });
    retrieveName.join();
}

注意:

  • 这不是生产中的事情。来自 join()的阻止调用在这里不是问题,但可能适用于长时间运行的CF.但是你显然无法从CF中提取异常直到它完成,所以 join()调用阻塞是有意义的。
  • 请记住,main()不在与CF相同的线程中运行。
  • 另一种方法(如果可行)可能是在 exceptionally()中处理所有必要的异常后操作(日志记录等),然后使用合适的返回值正常终止(例如& #34;处理异常!&#34;)而不是传播异常。
  • 您可以通过调用非阻止 isDone()方法来检查CF是否仍在运行。您还可以检查CF是否以异常( isCompletedExceptionally())结束或被取消( isCancelled())。