Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 作用域是否在引擎盖下无声地处理异常/故障?_Kotlin_Exception_Coroutine_Kotlin Coroutines - Fatal编程技术网

Kotlin 作用域是否在引擎盖下无声地处理异常/故障?

Kotlin 作用域是否在引擎盖下无声地处理异常/故障?,kotlin,exception,coroutine,kotlin-coroutines,Kotlin,Exception,Coroutine,Kotlin Coroutines,我有以下代码片段用于测试目的 fun main() { val myScope = CoroutineScope(Dispatchers.Default) + Job() myScope.launch { val job = async { delay(1000) throw RuntimeException("shiiiet") } try { job.await()

我有以下代码片段用于测试目的

fun main() {

   val myScope = CoroutineScope(Dispatchers.Default) + Job()

   myScope.launch {

       val job = async {
           delay(1000)
           throw RuntimeException("shiiiet")
       }

       try {
           job.await()
       } catch (ret: RuntimeException){
           throw RuntimeException("yooo!")
       }
   }

    try {
        Thread.sleep(5000)
    } catch(e: Exception){

    }

    println("wohoooo!") 
}
我以为流量永远不会到达最后一行,但我错了。我看到它印在屏幕上。我想到的原因是
launch
会将异常传播到父作用域,并且由于父作用域不处理它,它会在到达print语句时使JVM崩溃


这是因为父作用域在其子作用域失败、收到CancellationException并被忽略后被取消了吗

在您的示例中,您尝试了多种
throw
catch
方法

async
按预期工作-当您等待它时,您可以捕获异常。但是,如果您
启动一个协同例程,默认的
线程.uncaughtExceptionHandler
只会将结果打印到控制台

即使你这样做了

myScope.launch {
    ....
}.invokeOnCompletion { e -> println("Exception: $e") }
您仍然可以在控制台上获得额外的结果

本文解释了传播规则和处理异常的不同调用类型

有关如何在“main”co例程中捕获异常的示例:

fun main() = runBlocking {
    try {
        GlobalScope.launch {
            delay(10)
            throw Exception("You don't catch me in main.")
        }
        launch {
            delay(10)
            throw Exception("You catch me in main.")
        }
        delay(100)
        println("Never reached.")
    } catch(e: Exception) {
        println("Caught in main: ${e.cause}")
    }
    println("The end")
}

顶级
启动失败
不会使JVM崩溃,也不应该让JVM崩溃。崩溃的线程也不会使JVM崩溃。这是真的,但我不知何故认为异常会通过作用域一直传播到主线程。默认调度程序不负责主线程。在普通Java上,主线程甚至不运行事件循环,因此根本无法调度协同路由。您必须使用runBlocking在其上显式创建一个事件循环。您的代码总是打印
从未到达
以及
你看不见我。
此外,
分派器。Unconfined
不使用“主上下文”,不管这意味着什么,它在调用
launch
resume
的地方启动并恢复协同路由,在这些调用中,没有任何线程限制。Ups,用
你看不见我
我的意思是
你在main()里抓不到我
。。。。我需要再调查一下调度员。给我几个小时的时间…你不可能在一个线程中捕捉到一个并发启动的协同程序的异常,这个线程已经开始做其他事情了。只有在null分派的意外情况下,您才会看到由于上述原因而从
launch(Unconfined)
引发的异常,它在不分派的情况下执行。如果在抛出异常之前添加
delay(10)
,则该行为将在协同路由挂起时立即消失。然而,即使不挂起,我也无法从
launch
捕获异常。@Mark在进一步阅读和测试后,我删除了答案中的错误部分。谢谢你指出这一点。我添加了一个关于如何捕获“主协同例程”的示例……您所做的是捕获由失败的子协同例程导致的
CancellationException
。您没有捕获并处理原始异常,您只是将其作为取消原因附加。引发
CancellationException
的代码行是
delay(100)
,因为它是一个可取消的挂起调用。但是,这并没有阻止
runBlocking
作用域失败,因此这实际上并不构成异常处理。