1

这个问题特定于 Java 和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,而如果CompletableFuture第 2 步中返回的代码抛出,调用者只会在与返回的CompletableFuture.

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

这是另一个异步方法的示例invokeGet(),它调用get()并返回它返回的长度String

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 */
    }
}

我的问题是:

写得不好是get()因为它要求调用者进行这种复杂的异常处理,还是这是一种常见的模式?如果发生错误,返回 s 的异步方法是否应该CompletableFuture限制自己返回错误的期货,这样它们的调用者就不必编写这样的错误处理代码?

4

2 回答 2

0

简而言之,这取决于您自己的实现,但可以改进。如果您想通过不同的线程忽略、记录或对异常做出反应(这里的基本示例),让调用线程处理异常可能是有益的。但是,我见过的很多模式(见这篇文章的答案)会让你包含async带有 a 的函数try-catch-block并重新抛出一个对你的应用程序更有用的异常,由父线程处理,我认为这更好一点.

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

于 2018-08-16T19:22:01.377 回答
0

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

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

于 2018-08-17T10:26:59.050 回答