Какие способы обработки ошибок в корутинах вы знаете?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
-
Использование
try...catchблоков. Стандартный способ обработки исключений. Работает внутри корутины.// Применение try-catch suspend fun fetchData(): String { return try { // Операция, которая может выбросить исключение throw Exception("Ошибка загрузки данных") "Данные успешно загружены" } catch (e: Exception) { "Ошибка: ${e.message}" } }try...catchне подходит для обработки uncaught исключений, выброшенных из дочерних корутин, запущенных в другомCoroutineScope. -
CoroutineExceptionHandler. Перехватывает необработанные исключения, выброшенные корутинами, которые запущены в данномCoroutineScopeили в его дочернихCoroutineScope.// CoroutineExceptionHandler val handler = CoroutineExceptionHandler { _, exception -> println("Перехвачено исключение: $exception") } // Применение CoroutineExceptionHandler GlobalScope.launch(handler) { // Корутина, которая может выбросить исключение throw Exception("Ошибка в корутине") }CoroutineExceptionHandlerсрабатывает только для исключений, которые не обрабатываются механизмом структурированной конкурентности. -
SupervisorJobиsupervisorScope. В отличие от обычногоJob, когда дочерняя корутина с ошибкой приводит к отмене родительскогоJob,SupervisorJobне отменяет родительскийJobпри ошибке дочерней корутины.supervisorScopeсоздаетCoroutineScopeсSupervisorJob.// Использование supervisorScope suspend fun loadMultipleData() = supervisorScope { val data1 = async { // Может выбросить исключение throw Exception("Ошибка в данных 1") "Данные 1" } val data2 = async { "Данные 2" } // Можно обработать исключение для конкретной async try { println("Результат 1: ${data1.await()}") } catch (e: Exception) { println("Ошибка при загрузке данных 1: ${e.message}") } println("Результат 2: ${data2.await()}") }Используется для независимых дочерних задач, где ошибка одной не должна влиять на другие. Не заменяет
try...catchилиCoroutineExceptionHandler, скорее меняет поведение распространения исключений. -
Распространение исключений в структурированной конкурентности. По умолчанию, исключение в дочерней корутине отменяет родительскую корутину и всех ее сиблингов.
// Пример распространения исключения runBlocking { val job = launch { launch { // Дочерняя корутина 1 delay(100) throw Exception("Ошибка в дочерней 1") } launch { // Дочерняя корутина 2 delay(200) println("Дочерняя 2 выполнилась") } } try { job.join() } catch (e: Exception) { println("Исключение перехвачено в родительской: $e") } }Это базовое поведение структурированной конкурентности, которое помогает избежать утечек ресурсов и состояний.
-
Использование
asyncсawait(). Исключения, выброшенные вasync, не распространяются автоматически. Они хранятся внутриDeferredи выбрасываются только при вызовеawait().// Обработка исключений с async/await suspend fun safeAsyncCall() = coroutineScope { val deferred = async { throw Exception("Ошибка в async") "Результат async" } try { val result = deferred.await() println("Результат: $result") } catch (e: Exception) { println("Перехвачено исключение из async: ${e.message}") } }Это позволяет выборочно обрабатывать ошибки для каждой асинхронной задачи.
| Способ | Назначение | Обрабатывает uncaught? | Изменяет распространение? |
|---|---|---|---|
try...catch |
Обработка исключений внутри текущей корутины | Нет | Нет |
CoroutineExceptionHandler |
Перехват необработанных исключений в Scope | Да | Нет |
SupervisorJob/Scope |
Изменение поведения распространения исключений | Нет | Да |
| Структурированная конкурентность | Автоматическая отмена при ошибке | Да | Да |
async + await() |
Отложенное распространение исключения | Нет | Да (до await) |