Что произойдет с корутиной, когда возникает исключение?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
При возникновении исключения внутри корутины зависимость от типа исключения (и настроек диспетчера/контекста) определяет, как оно будет обработано.
-
Нерегулируемое исключение: Если исключение не перехвачено внутри корутины, оно propagate вверх по иерархии корутин до ближайшего родительского
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("Coroutine 1 started")
delay(100)
throw RuntimeException("Something went wrong in Coroutine 1")
} catch (e: Exception) {
println("Coroutine 1 caught exception: ${e.message}")
}
}
scope.launch {
println("Coroutine 2 started")
delay(500)
println("Coroutine 2 finished")
}
delay(1000) // Ждем, чтобы увидеть вывод
scope.cancel() // Отменяем scope
}
В этом примере, исключение в Coroutine 1 перехватывается, и Coroutine 2 продолжает выполнение, потому что используется SupervisorJob. Если бы вместо SupervisorJob использовался обычный Job, исключение в Coroutine 1 привело бы к отмене Coroutine 2.