提问者:小点点

从返回CompletableFuture的异步方法的同步部分抛出异常


这个问题是针对Java和< code>CompletableFuture的。

如果我有一个像下面这样的异步方法,

CompletableFuture<String> get() {
    /* Step #1: Do some sync prep work */
    String s = doSomethingSync();

    /* Step #2: Do something async (returning CompletableFuture) */
    return doSomethingAsync(s);
}

如果步骤#1中的代码抛出,get()的调用者将在获得它返回的CompletableFuture之前获得异常,而如果步骤#2中返回的CompletableFuture中的代码抛出,调用者将仅在与返回的CompletableFuture交互时获得异常。

这表明get()的调用方应该编写一些复杂的异常处理代码来处理这两种情况。

下面是另一个异步方法的示例,invokeGet(),该方法调用get()并返回它返回的字符串长度:

CompletableFutre<Integer> InvokeGet() {
    try {
        CompletableFuture future = get();
        return furure.handle((result, throwable) -> {
           if (throwable != null) {
               /* Handle exception thrown in step #2 in get(), e.g. rethrow */
           } else {
               return result.length();
           }
        });
    } catch (Exception e) {
        /* Handle exception thrown in step #1 in get() */
        /* Return some value or throw */
    }
}

我的问题是:

< code>get()写得不好是因为它要求其调用方进行这种复杂的异常处理,还是这是一种常见的模式?返回< code>CompletableFuture的异步方法是否应该局限于在出错时返回出错的未来,以便它们的调用方不必编写这样的错误处理代码?


共2个答案

匿名用户

简而言之,这取决于您自己的实现,但它可以改进。如果您想忽略、记录异常,或者通过不同的线程对异常做出反应,那么让调用线程处理异常可能会很有用(这里是基本示例)。然而,我看到的许多模式(见本文答案)都会让您使用try-catch块包含asyncfunction,并重新抛出一个对您的应用程序更有用的异常,由父线程处理,我认为这会更好一些。

如果您正在寻找不同的异常处理,请参阅本文以获取不同处理的示例。

匿名用户

我认为为参数验证抛出异常是合适的,因为调用方不应该处理这些异常——非法参数是一个必须修复的bug。

但是,最好将其他异常放在返回的CompletableFuture中,以便调用者可以使用标准的CompletableFuture异常处理和链接。同样,您不会返回null未来,而是返回用null完成的未来。另请参阅已完成的CompletableFuture,但有异常。

相关问题