从异步方法抛出异常是否合理?

Mig*_*boa 5 java multithreading asynchronous promise completable-future

在Java中开发一个带有CompletableFuture返回类型的异步方法,我们希望生成的CF能够正常或异常地完成,具体取决于该方法是成功还是失败.

但是,例如,考虑我的方法写入AsynchronousChannel并获得打开该通道的异常.它甚至没有开始写作.所以,在这种情况下,我正在试图让异常流向调用者.那是对的吗?

虽然调用者必须处理2种失败情况:1)异常,或2)拒绝承诺.

或者,我的方法应该捕获该异常并返回被拒绝的承诺吗?

Ped*_*lix 2

IMO,选项 1) 使 API 更难使用,因为有两种不同的路径来传递错误:

  1. “同步”异常,其中方法结束抛出异常。
  2. “异步”异常,其中方法返回 CF,该 CF 以异常完成。请注意,这种情况是无法避免的,因为总是存在只有在异步路径启动后才发现错误的情况(例如超时)。

程序员现在必须确保这两条路径都得到正确处理,而不仅仅是一条。

async同样有趣的是,C# 和 Javascript 的行为都是始终通过返回的Task/报告函数体内抛出的异常Promise,即使是在第一个之前抛出的异常await,并且从不以async异常结束函数调用。

Kotlin 的协程也是如此,即使在使用Unconfined调度程序时也是如此

class SynchronousExceptionExamples {
    @Test
    fun example() {
        log.info("before launch")
        val job = GlobalScope.launch(Dispatchers.Unconfined) {
            log.info("before throw")
            throw Exception("an-error")
        }
        log.info("after launch")
        Thread.sleep(1000)
        assertTrue(job.isCancelled)
    }
}
Run Code Online (Sandbox Code Playgroud)

将产生

6 [main] INFO SynchronousExceptionExamples - before launch
73 [main @coroutine#1] INFO SynchronousExceptionExamples - before throw
(...)
90 [main] INFO SynchronousExceptionExamples - after launch
Run Code Online (Sandbox Code Playgroud)

请注意,异常发生在main线程中,但launch以正确的Job.