try - catch块
- 原理:在协程代码块内使用
try - catch
,其原理与普通Java或Kotlin代码中的try - catch
类似,通过在try
块中包裹可能抛出异常的代码,catch
块捕获并处理异常。协程的挂起函数同样可以被包裹在try - catch
块中,当挂起函数抛出异常时,catch
块能够捕获。
- 使用场景:适用于在单个协程内部对特定的、已知类型的异常进行捕获和处理。例如,在执行网络请求的协程中,处理可能的
IOException
等网络相关异常。
- 示例:
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
launch {
throw IOException("Network error")
}.join()
} catch (e: IOException) {
println("Caught IOException: $e")
}
}
CoroutineExceptionHandler
- 原理:
CoroutineExceptionHandler
是一个用于处理未捕获异常的处理器。当协程因未被try - catch
捕获的异常而终止时,会调用CoroutineExceptionHandler
的handleException
方法。它可以被添加到CoroutineScope
中,用于处理该作用域内所有未捕获异常。
- 使用场景:适用于在多个协程间统一处理未捕获异常,例如在整个应用的全局协程作用域中,对所有未处理异常进行日志记录、崩溃上报等通用处理。
- 示例:
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
fun main() = runBlocking {
GlobalScope.launch(handler) {
throw IOException("Network error")
}
delay(1000)
}
supervisorScope
- 原理:
supervisorScope
创建了一个特殊的协程作用域,在这个作用域内启动的子协程不会因为其他子协程的异常而取消。当一个子协程抛出异常时,只有该子协程会被取消,其他子协程继续执行。异常会向上传播到supervisorScope
的调用者,如果没有处理,最终会导致整个supervisorScope
失败。
- 使用场景:适用于多个子协程之间相对独立,单个子协程的失败不应影响其他子协程执行的场景。比如在批量处理任务时,每个任务作为一个子协程,个别任务失败不影响其他任务继续执行。
- 示例:
import kotlinx.coroutines.*
fun main() = runBlocking {
supervisorScope {
launch {
delay(1000)
println("Task 1 completed")
}
launch {
throw IOException("Task 2 failed")
}
launch {
delay(2000)
println("Task 3 completed")
}
}
println("All tasks are done (or failed)")
}
区别
- 作用范围:
try - catch
作用于单个协程代码块内部,对局部代码异常进行捕获。
CoroutineExceptionHandler
作用于整个CoroutineScope
,处理该作用域内所有未捕获异常。
supervisorScope
影响其内部启动的所有子协程间异常传播关系。
- 异常处理方式:
try - catch
主动捕获异常并进行处理。
CoroutineExceptionHandler
统一处理未捕获异常。
supervisorScope
改变异常传播行为,防止子协程间相互影响。
- 适用场景:
try - catch
适合处理已知特定异常。
CoroutineExceptionHandler
适合全局统一处理未捕获异常。
supervisorScope
适合多个相对独立子协程的场景。