В чем разница между обработкой ошибки в корутине с помощью try/catch и CoroutineExceptionHandler?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между try/catch и CoroutineExceptionHandler в Kotlin
Это два фундаментально разных подхода к обработке ошибок в корутинах, каждый имеет свою область применения.
try/catch для обработки обычных исключений
try/catch — это стандартный механизм обработки исключений, который синхронно ловит ошибки в коде корутины. Это работает так же, как в обычном коде:
launchIO {
try {
val data = fetchDataFromNetwork() // может выбросить исключение
updateUI(data)
} catch (e: Exception) {
showError(e.message)
}
}
Это локальный способ обработки: вы явно указываете, какой код может выбросить ошибку, и как её обработать. Плюсы:
- Явная обработка в том месте, где она нужна
- Точный контроль над типами исключений
- Полная типизация (обработка IOException отдельно от NetworkException)
CoroutineExceptionHandler для глобальной обработки
CoroutineExceptionHandler — это глобальный обработчик ошибок для корутины, который ловит необработанные исключения на уровне всей корутины. Это не касается исключений, которые были обработаны try/catch:
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
showGlobalError(exception.message)
logError(exception)
}
viewModelScope.launch(exceptionHandler) {
val data = fetchDataFromNetwork() // если исключение не обработано локально
updateUI(data)
}
Ключевая разница
| Параметр | try/catch | CoroutineExceptionHandler |
|---|---|---|
| Область | Локальная, в пределах блока | Глобальная для всей корутины |
| Срабатывание | На месте выброса исключения | Только если исключение не обработано локально |
| Использование | Обработка конкретных ошибок | Сетка безопасности для критических ошибок |
| Множественные блоки | Можно иметь несколько try/catch в одной корутине | Один обработчик на корутину |
Практический пример
val handler = CoroutineExceptionHandler { _, exception ->
// Вызовется ТОЛЬКО если исключение не обработано локально
Log.e("Global", "Необработанная ошибка: ${exception.message}")
showCrashDialog()
}
viewModelScope.launch(handler) {
try {
// Эта ошибка будет обработана здесь
val userData = fetchUser() // выброситься ParsingException
} catch (e: ParsingException) {
showUserMessage("Ошибка парсинга")
// handler НЕ сработает, так как мы обработали ошибку
}
// Эта ошибка попадёт в handler
val posts = fetchPosts() // выбросится NetworkException
}
Когда что использовать
try/catch — когда вы знаете, что может пойти не так, и готовы обработать это:
- Парсинг JSON
- Сетевые запросы в наивысшей точке иерархии бизнес-логики
- Работа с файлами
- Валидация пользовательского ввода
CoroutineExceptionHandler — для страховки от неожиданных ошибок:
- Необработанные исключения в async блоках
- Критические ошибки, которые должны упасть приложение или вывести пользователю сообщение
- Логирование всех необработанных ошибок
Оптимальный подход — комбинировать оба: используйте try/catch для известных ошибок, а CoroutineExceptionHandler как финальную сеть безопасности.