> Что такое CoroutineExceptionHandler (Kotlin, Android)

Уровень: junior · Роль: mobile · Категория: Технические вопросы

Компании: MTS, Юрент, Совкомбанк

Стек: Kotlin, Android

> Пример ответа

Короткий ответ

CoroutineExceptionHandler - это механизм в Kotlin Coroutines для перехвата необработанных исключений, возникающих в корутинах. Он устанавливается через CoroutineContext и вызывается, когда исключение не было обработано внутри корутины. Это аналог Thread.UncaughtExceptionHandler, но для корутин. Используется для централизованной обработки ошибок, например, логирования или показа пользователю.

Подробное объяснение

CoroutineExceptionHandler - это элемент CoroutineContext, который реализует интерфейс CoroutineExceptionHandler. Он перехватывает исключения, которые выходят за пределы корутины и не были обработаны внутри неё (например, через try-catch или runCatching).

Важные особенности:

  • Обработчик вызывается только для исключений, которые не были перехвачены внутри корутины.
  • Он не работает с исключениями, которые передаются через CancellationException (отмена корутины) - они обрабатываются отдельно.
  • Если обработчик не установлен, исключение будет передано в Thread.uncaughtExceptionHandler текущего потока.
  • В CoroutineScope обработчик можно установить через CoroutineExceptionHandler в контексте, но для async и launch поведение отличается: async передаёт исключение в Deferred, а launch - в обработчик.
  • Обработчик не заменяет try-catch - он предназначен для глобальной обработки ошибок, а не для локальной.

На практике

На Android CoroutineExceptionHandler часто используется в ViewModel или Application для централизованного логирования ошибок. Например, можно создать общий обработчик, который отправляет ошибку в Crashlytics или показывает сообщение пользователю.

Важно помнить: обработчик не должен выполнять тяжёлые операции или блокировать поток. Он вызывается в контексте, где произошло исключение, поэтому лучше использовать его только для логирования или уведомления.

Пример кода

val handler = CoroutineExceptionHandler { _, throwable ->
    Log.e("App", "Uncaught coroutine exception", throwable)
}

val scope = CoroutineScope(Dispatchers.Main + handler)

scope.launch {
    throw RuntimeException("Something went wrong")
}
// В логах появится сообщение с ошибкой

Пример с async:

val scope = CoroutineScope(Dispatchers.Main + handler)

scope.launch {
    val deferred = async {
        throw RuntimeException("Error in async")
    }
    try {
        deferred.await()
    } catch (e: Exception) {
        // Обработка локально
    }
}
// Здесь handler не вызовется, так как исключение перехвачено через await()

Как отвечать на собеседовании

Начни с определения: "это элемент контекста корутины для перехвата необработанных исключений". Затем поясни, когда он срабатывает: только для launch, не для async (если исключение не проброшено через await). Упомяни, что CancellationException не обрабатывается. Приведи пример использования на Android - логирование в Crashlytics. Если спросят про отличие от try-catch, скажи, что try-catch - локальная обработка, а CoroutineExceptionHandler - глобальная.

Что проверяет интервьюер

Интервьюер проверяет:

  • Понимание модели исключений в корутинах.
  • Знание разницы между launch и async в контексте обработки ошибок.
  • Понимание, что CoroutineExceptionHandler не перехватывает CancellationException.
  • Умение применять обработчик на практике (например, в Android-приложениях).
  • Осознание ограничений: обработчик не заменяет локальную обработку ошибок.

Типичные ошибки

  • Утверждение, что CoroutineExceptionHandler перехватывает все исключения, включая CancellationException.
  • Попытка использовать обработчик для async - это не сработает, если не вызвать await().
  • Установка обработчика в SupervisorJob и ожидание, что он перехватит ошибки дочерних корутин - это работает, но только для launch.
  • Забывают, что обработчик вызывается в контексте, где произошла ошибка, и не должен блокировать поток.
  • Использование обработчика вместо try-catch для локальной обработки - это неправильно, так как он не даёт доступа к контексту выполнения.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью