面试题答案
一键面试Kotlin协程中未捕获异常的默认处理机制
在Kotlin协程中,未捕获的异常默认会导致协程取消,并向上传播给父协程。如果到达顶层协程仍未处理,该异常会被发送到CoroutineExceptionHandler
。若没有为协程作用域设置CoroutineExceptionHandler
,则异常会通过Thread.UncaughtExceptionHandler
处理,默认情况下会使当前线程终止(如果协程在主线程中运行,这将导致应用崩溃)。
父子协程场景下处理异常
在父子协程中,子协程的异常默认会导致父协程取消。可以通过在父协程作用域设置CoroutineExceptionHandler
来捕获子协程的异常。
import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val parentJob = GlobalScope.launch(handler) {
launch {
throw RuntimeException("Child coroutine exception")
}
}
parentJob.join()
}
在此例中,CoroutineExceptionHandler
设置在父协程的GlobalScope.launch
中,当子协程抛出异常时,CoroutineExceptionHandler
会捕获并处理该异常,防止异常向上传播导致程序崩溃。
并发协程场景下处理异常
在并发协程场景下,并发运行的多个协程之间没有父子关系。可以为每个协程单独设置CoroutineExceptionHandler
,或者为它们共同的作用域设置CoroutineExceptionHandler
。
import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job1 = GlobalScope.launch(handler) {
throw RuntimeException("First concurrent coroutine exception")
}
val job2 = GlobalScope.launch(handler) {
delay(100)
println("Second concurrent coroutine is still running")
}
job1.join()
job2.join()
}
在此例中,为每个并发协程都设置了相同的CoroutineExceptionHandler
。当job1
抛出异常时,CoroutineExceptionHandler
捕获并处理异常,job2
不受影响继续运行,确保程序的稳定性和健壮性。