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

Стоит ли использовать общий Exception для ошибок?

2.0 Middle🔥 182 комментариев
#Архитектура и паттерны

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

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

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

Почему использование общего Exception — это антипаттерн

Использование общего класса Exception (или Throwable) для обработки всех ошибок в Android-разработке — это серьёзная архитектурная ошибка, которая приводит к хрупкости кода, сложностям в поддержке и непредсказуемому поведению приложения. Вот развернутое объяснение, почему этого следует избегать.

Ключевые проблемы общего Exception

  1. Потеря семантики ошибок Когда вы перехватываете Exception, вы стираете разницу между критическими сбоями (например, IOException при работе с сетью) и логическими ошибками (например, IllegalArgumentException). Это делает код нечитаемым и усложняет отладку.

    // ❌ Плохо: нельзя понять, какая именно ошибка произошла
    try {
        fetchDataFromNetwork()
    } catch (e: Exception) {
        showError("Что-то пошло не так")
    }
    
    // ✅ Правильно: обрабатываем конкретные исключения
    try {
        fetchDataFromNetwork()
    } catch (e: IOException) {
        showError("Проблема с интернетом")
    } catch (e: JsonSyntaxException) {
        showError("Ошибка формата данных")
    }
    
  2. Скрытие багов и непредвиденных ошибок Общий Exception может перехватывать ошибки программирования, которые должны исправляться разработчиком, а не обрабатываться в рантайме. Например, NullPointerException, ClassCastException или IllegalStateException.

    // ❌ Опасный код: скрываем реальную проблему
    fun updateUser(user: User?) {
        try {
            val name = user!!.name // Может выбросить NPE
        } catch (e: Exception) {
            Log.e("TAG", "Ошибка") // Реальная причина теряется
        }
    }
    
  3. Нарушение принципа единственной ответственности Обработчик общего Exception вынужден содержать сложную логику для определения типа ошибки, что превращает его в God-объект.

Правильные альтернативы и best practices

  1. Используйте конкретные типы исключений

    • Для сетевых ошибок — IOException, SocketTimeoutException
    • Для парсинга данных — JsonSyntaxException, XmlPullParserException
    • Для бизнес-логики — создавайте собственные исключения
    // Собственное исключение для бизнес-логики
    class InsufficientFundsException(message: String) : RuntimeException(message)
    
    fun makePayment(amount: Double) {
        if (balance < amount) {
            throw InsufficientFundsException("Недостаточно средств")
        }
    }
    
  2. Разделяйте обработку проверяемых и непроверяемых исключений

    • Проверяемые (checked): Ошибки, которые можно предвидеть (ввод-вывод, парсинг). Обрабатывайте явно.
    • Непроверяемые (unchecked): Ошибки программирования (NPE, аргументы). Не перехватывайте глобально, исправляйте код.
  3. Используйте Result-обертки в Kotlin Современный подход — использование sealed-классов или класса Result для типобезопасной обработки ошибок.

    sealed class NetworkResult<out T> {
        data class Success<T>(val data: T) : NetworkResult<T>()
        data class Error(val exception: Throwable) : NetworkResult<Nothing>()
    }
    
    suspend fun fetchData(): NetworkResult<String> = try {
        NetworkResult.Success(apiService.getData())
    } catch (e: IOException) {
        NetworkResult.Error(e)
    } // Не перехватываем Exception!
    
  4. Глобальная обработка только на верхнем уровне В Android есть места, где общий Exception допустим, но с ограничениями:

    • В Thread.setDefaultUncaughtExceptionHandler для логирования критических сбоев
    • В корне корутины с CoroutineExceptionHandler
    • В RxJava через onErrorReturn
    // Пример правильного глобального обработчика в корутине
    val handler = CoroutineExceptionHandler { _, exception ->
        when (exception) {
            is IOException -> logNetworkError(exception)
            is SecurityException -> logPermissionError(exception)
            else -> logCriticalError(exception) // Только для действительно неожиданных ошибок
        }
    }
    

Когда общий Exception допустим (с осторожностью)

  1. Логирование в глобальных обработчиках перед падением приложения
  2. Тестовые среды, где нужно гарантированно очистить состояние
  3. Временные решения при рефакторинге legacy-кода

Вывод

Использование общего Exception — это антипаттерн, который нарушает основные принципы чистого кода. Вместо этого применяйте:

  • Конкретные типы исключений для ясности
  • Result-обертки для функционального подхода
  • Глобальные обработчики только для логирования непредвиденных ошибок
  • Собственные исключения для бизнес-логики

Помните: чем точнее вы обрабатываете ошибки, тем стабильнее ваше приложение и проще его поддерживать. Исключения — это не просто техническая необходимость, а важная часть доменной модели вашего приложения.

Стоит ли использовать общий Exception для ошибок? | PrepBro