← Назад к вопросам

Какие знаешь способы работы с исключениями в корутинах кроме try-catch?

2.0 Middle🔥 151 комментариев
#Kotlin основы#Многопоточность и асинхронность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Работа с исключениями в корутинах: подходы помимо try-catch

В корутинах Kotlin исключения обрабатываются не только классическим try-catch, но и с помощью специальных механизмов, учитывающих структурную конкурентность (structured concurrency). Вот основные альтернативные подходы:

1. Обработка исключений в корутинах с помощью CoroutineExceptionHandler

CoroutineExceptionHandler — это контекстный элемент для глобальной обработки необработанных исключений в корутинах. Он используется в корне корутины или в SupervisorJob.

val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
    println("Поймано исключение: ${throwable.message}")
}

fun main() = runBlocking {
    val job = launch(exceptionHandler) {
        throw RuntimeException("Ошибка в корутине")
    }
    job.join()
}

2. Использование SupervisorJob и SupervisorScope

Обычный Job отменяет все дочерние корутины при исключении в одной из них. SupervisorJob позволяет изолировать исключения:

fun main() = runBlocking {
    val supervisorJob = SupervisorJob()
    val scope = CoroutineScope(coroutineContext + supervisorJob)
    
    val child1 = scope.launch {
        delay(100)
        throw RuntimeException("Ошибка в первой корутине")
    }
    
    val child2 = scope.launch {
        delay(200)
        println("Вторая корутина работает несмотря на ошибку в первой")
    }
    
    joinAll(child1, child2)
}

Аналогично работает supervisorScope:

supervisorScope {
    launch {
        throw RuntimeException("Локальная ошибка")
    }
    launch {
        delay(100) // Эта корутина продолжит работу
        println("Другая задача")
    }
}

3. Обработка через async/await и Deferred

При использовании async исключения не выбрасываются немедленно, а сохраняются в Deferred и выбрасываются только при вызове await():

fun main() = runBlocking {
    val deferred = async {
        throw RuntimeException("Асинхронная ошибка")
    }
    
    try {
        deferred.await()
    } catch (e: Exception) {
        println("Исключение поймано при await: ${e.message}")
    }
}

4. Использование функции runCatching

Функция runCatching предоставляет функциональный стиль обработки исключений:

fun main() = runBlocking {
    val result = runCatching {
        // Код, который может выбросить исключение
        throw RuntimeException("Ошибка")
    }
    
    result.onFailure { e ->
        println("Обработано исключение: ${e.message}")
    }
    
    val recoveredValue = result.getOrElse { 
        "Значение по умолчанию"
    }
}

5. Комбинирование подходов в корутин-скопах

На практике часто комбинируют несколько подходов:

fun main() = runBlocking {
    val handler = CoroutineExceptionHandler { _, e ->
        println("Глобальный обработчик: ${e.message}")
    }
    
    val scope = CoroutineScope(SupervisorJob() + handler)
    
    scope.launch {
        // Код, который может упасть
    }
    
    scope.launch {
        // Другой независимый код
    }
}

6. Важные отличия от обычной обработки исключений

  • Отмена корутин: В корутинах исключение автоматически отменяет родительскую корутину (кроме SupervisorJob)
  • Прозрачность исключений: Исключения в async не выбрасываются до await()
  • Контекст выполнения: Исключения распространяются через иерархию корутин

7. Рекомендации по использованию

  1. Для фоновых задач используйте CoroutineExceptionHandler с логированием
  2. Для независимых операций применяйте SupervisorJob или supervisorScope
  3. Для асинхронных вычислений с результатом используйте async с обработкой при await()
  4. Всегда учитывайте отмену корутин при исключениях

Эти механизмы обеспечивают более декларативный и безопасный подход к обработке ошибок в асинхронном коде, чем традиционный try-catch, особенно в сложных иерархиях корутин.

Какие знаешь способы работы с исключениями в корутинах кроме try-catch? | PrepBro