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

В чем разница между error и exception?

1.0 Junior🔥 181 комментариев
#Dart

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

Разница между Error и Exception в Dart/Flutter

В Dart существует ясное различие между Error и Exception. Хотя оба наследуются от Throwable, они используются для разных ситуаций и имеют разные предназначения.

Exception — ожидаемые ошибки

Exception — это исключение, которое может произойти во время выполнения программы и которое разумно обрабатывать. Это программные ошибки, которые предусмотрены и должны быть обработаны.

// Встроенные типы Exception
try {
  int result = 10 ~/ 0; // IntegerDivisionByZeroException
} on IntegerDivisionByZeroException {
  print("Cannot divide by zero");
}

try {
  List<int> list = [1, 2, 3];
  print(list[10]); // RangeError
} on RangeError catch (e) {
  print("Index out of bounds: $e");
}

// Custom Exception
class UserNotFoundException implements Exception {
  final String message;
  UserNotFoundException(this.message);
  
  @override
  String toString() => "User not found: $message";
}

Future<User> fetchUser(String id) async {
  final response = await http.get(Uri.parse("/api/users/$id"));
  if (response.statusCode == 404) {
    throw UserNotFoundException(id);
  }
  return User.fromJson(json.decode(response.body));
}

// Использование
try {
  final user = await fetchUser("123");
} on UserNotFoundException catch (e) {
  print("Error: $e");
} on SocketException catch (e) {
  print("Network error: $e");
} catch (e) {
  print("Unknown error: $e");
}

Error — непредвиденные критические ошибки

Error — это неисправимая ошибка, которая указывает на серьёзную проблему в коде или окружении. Errors НЕ должны обрабатываться, так как они указывают на проблему, которую нужно исправить в коде.

// Встроенные типы Error

// StackOverflowError — бесконечная рекурсия
int recursion(int n) {
  return recursion(n + 1); // StackOverflowError
}

// OutOfMemoryError — закончилась память
final hugeList = List<int>.generate(999999999999, (i) => i); // OutOfMemoryError

// NoSuchMethodError — метод не существует
class MyClass {}
MyClass obj = MyClass();
obj.nonExistentMethod(); // NoSuchMethodError

// AssertionError — assertion не выполнился
class User {
  final String email;
  
  User(this.email) {
    assert(email.contains('@'), 'Invalid email format');
  }
}

// TypeError — неправильный тип (выявляется в runtime в некоторых случаях)
dynamic value = "string";
int result = value as int; // CastError (подтип TypeError)

Главные различия

АспектExceptionError
ПредназначениеОбработка ошибок приложенияКритические сбои
ОжидаемостьОжидаемое, может произойтиНепредвиденное, не должно
ОбработкаДолжна обрабатыватьсяНе должна обрабатываться
ПримерыFileNotFound, NetworkErrorStackOverflow, OutOfMemory
НаследованиеРеализует ExceptionНаследует Error
catch()Можно ловитьНежелательно ловить

Структура иерархии

Object
  └─ Throwable
      ├─ Exception (Ловим и обрабатываем)
      │   ├─ ArgumentError
      │   ├─ FormatException
      │   ├─ StateError
      │   └─ Custom exceptions (UserNotFoundException и т.д.)
      │
      └─ Error (Не ловим)
          ├─ AssertionError
          ├─ TypeError
          ├─ NoSuchMethodError
          ├─ StackOverflowError
          └─ OutOfMemoryError

Практические примеры во Flutter

Правильная обработка Exception:

Future<void> loadUserData() async {
  try {
    final userId = await getUserIdFromSharedPrefs();
    final user = await fetchUser(userId);
    setState(() => _user = user);
  } on SocketException {
    _showSnackBar("Network error. Check your connection");
  } on TimeoutException {
    _showSnackBar("Request timed out. Try again");
  } on UserNotFoundException {
    _showSnackBar("User not found");
  } catch (e) {
    _showSnackBar("Unknown error: $e");
  }
}

Плохая практика — обработка Error:

// ❌ Не делай так!
try {
  myFunction();
} catch (e) {
  print("Error: $e"); // Может поймать Error, что скрывает проблему
}

// ❌ И уж совсем плохо — обработка всего подряд
try {
  myFunction();
} catch (e) {
  // Это скроет реальные проблемы в коде
}

Правильная практика:

// ✅ Ловим только Exception
try {
  myFunction();
} on TimeoutException catch (e) {
  // Обрабатываем ожидаемую ошибку
} on Exception catch (e) {
  // Обрабатываем другие исключения
} catch (e, stackTrace) {
  // Если всё же что-то неожиданное, логируем для debug
  debugPrintStack(label: "Unexpected error: $e", stackTrace: stackTrace);
  rethrow; // Пробрасываем выше
}

Custom Exception vs Error

Создавай Custom Exception для ожидаемых ошибок:

// ✅ Exception для логики приложения
class InvalidCredentialsException implements Exception {
  final String message;
  InvalidCredentialsException(this.message);
  
  @override
  String toString() => message;
}

// Использование
try {
  final user = await login(email, password);
} on InvalidCredentialsException catch (e) {
  showDialog(context: context, message: e.toString());
}

Errors — это признак проблемы в коде:

// ❌ Error указывает на ошибку программиста
class User {
  User(String name) {
    if (name.isEmpty) {
      throw AssertionError("Name cannot be empty");
    }
  }
}

// ✅ Используй Exception для проверки при компиляции
class User {
  User(String name) {
    if (name.isEmpty) {
      throw ArgumentError("Name cannot be empty");
    }
  }
}

Заключение

  • Exception — обрабатывай: сетевые ошибки, валидация, состояние приложения
  • Error — не обрабатывай: указывает на ошибку в коде, которую нужно исправить
  • Всегда будь специфичным в catch блоках, не ловись всё подряд
  • Используй Custom Exception для явного описания ошибок твоего приложения