面试题答案
一键面试在协程内部处理异常
- 使用try - catch块
- 示例代码:
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
val result = withContext(Dispatchers.Default) {
throw RuntimeException("模拟异常")
"任务完成"
}
println(result)
} catch (e: Exception) {
println("捕获到异常: $e")
}
}
- **适用场景**:适用于需要在特定的协程代码块中,对可能出现的异常进行精细控制的场景。例如,当某个协程执行特定的业务逻辑,而你希望在该业务逻辑出错时进行相应处理,比如记录日志、进行补偿操作等。
2. 使用coroutineExceptionHandler - 示例代码:
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, exception ->
println("全局异常处理: $exception")
}
fun main() = runBlocking {
GlobalScope.launch(handler) {
throw RuntimeException("模拟异常")
}
delay(1000)
}
- **适用场景**:适用于处理多个协程或整个应用程序范围内的异常。比如在一个大型项目中,多个地方启动了协程,希望有一个统一的异常处理机制来记录日志、通知用户等,而不需要在每个协程中都写try - catch块。
在协程之间处理异常
- 父协程与子协程关系中的异常处理
- 默认行为:在Kotlin协程中,子协程抛出的未处理异常会向上传播到父协程,导致父协程也会异常结束。
- 示例代码:
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
launch {
throw RuntimeException("子协程异常")
}
}
try {
job.join()
} catch (e: Exception) {
println("父协程捕获到异常: $e")
}
}
- **适用场景**:当子协程的异常会影响到父协程的整体逻辑时,父协程需要捕获并处理子协程的异常,以决定后续的操作,比如是否要继续执行其他子协程或进行整体的清理工作。
2. 使用supervisorJob - 示例代码:
import kotlinx.coroutines.*
fun main() = runBlocking {
val supervisor = SupervisorJob()
val scope = CoroutineScope(supervisor + Dispatchers.Default)
scope.launch {
throw RuntimeException("子协程异常")
}
scope.launch {
println("另一个子协程继续执行")
}
delay(1000)
}
- **适用场景**:当希望子协程之间相互独立,一个子协程的异常不影响其他子协程的执行时,使用supervisorJob。比如在一个并行处理多个任务的场景中,某个任务失败不应导致其他任务中断。