Какво се случва с корутината, когато възникне изключение?
sobes.tech AI
Отговор от AI
При възникване на изключение вътре в корутина, зависимостта от типа на изключението (и настройките на диспетчера/контекста) определя как ще бъде обработено.
-
Нерегулирано изключение: Ако изключението не бъде хванато вътре в корутината, то се пропагира нагоре по йерархията на корутините до най-близкия родителски
Job(илиCoroutineScope). Поведението зависи от типа наJob:Job: По подразбиране, ако възникне изключение в дъщерна корутина, родителскиятJobсе отменя, което води до отменяне на всички останали негови дъщерни корутини. Изключението се прехвърля нагоре.SupervisorJob: РодителскиятSupervisorJobне се отменя при възникване на изключение в дъщерна корутина. Само самата корутина, в която е възникнало изключението, се отменя. Това е полезно, когато е необходимо отменянето на една дъщерна задача да не влияе на другите.- Кореновият
CoroutineScope: Ако изключението достигне до кореновияCoroutineScope(например,GlobalScopeили scope, създаден с помощта наCoroutineScopeбезJob), то се предава към глобалния обработчик на изключенияCoroutineExceptionHandler. По подразбиране, ако няма регистриран обработчик, изключението се логва вSystem.err.
-
Хванато изключение: Ако изключението бъде хванато с помощта на
try-catchблок вътре в корутината, то се обработва локално, и корутината продължава изпълнението си след блокаcatch, ако е възможно. Изключението не се прехвърля нагоре. -
Изключения, свързани с отменяне (например,
CancellationException): Тези изключения са специални. Те се използват за механизма на отменяне на корутините и обикновено се игнорират от повечето обработчици на изключения по подразбиране. Те не водят до фатален срив на родителскияJobпо подразбиране. -
Изключения в
async: Корутината, стартирана чрезasync, поставя изключението в свояDeferred. Изключението се прехвърля само при извикване на.await()върху тозиDeferred. До тогава изключението е "скрито".
import kotlinx.coroutines.*
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob())
scope.launch {
try {
println("Корутината 1 започна")
delay(100)
throw RuntimeException("Нещо се обърка в Корутината 1")
} catch (e: Exception) {
println("Хваната изключение в Корутината 1: ${e.message}")
}
}
scope.launch {
println("Корутината 2 започна")
delay(500)
println("Корутината 2 приключи")
}
delay(1000) // Изчакваме, за да видим изхода
scope.cancel() // Отменяме scope
}
В този пример, изключението в Корутината 1 е хванато, и Корутината 2 продължава изпълнението си, защото е използван SupervisorJob. Ако беше използван обикновен Job, изключението в Корутината 1 щеше да доведе до отменяне на Корутината 2.