Назад к вопросам
Middle
134
questionbank

Какие способы обработки ошибок в корутинах вы знаете?

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)