Обработка ошибок

Errors Exceptions

Обработка ошибок — это критически важная часть любого надежного программного обеспечения.

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

В Dart ошибки делятся на два основных типа:

Основной механизм работы с исключениями

try, catch, finally

Например

Dart
Светлая тема Темная тема
void main() {
  String text = 'Изучаем HTTP'; // Эта строка не может быть преобразована в число

  try {
    // Потенциально опасная операция
    // "Пытаемся" её выполнить
    int number = int.parse(text);
    print('Число: $number');
  } catch (e) { // e - это объект исключения
    print('Произошла ошибка: $e');
    print('Тип ошибки: ${e.runtimeType}'); // Показывает тип исключения
  }

  print('Программа продолжает выполнение.');
}
Вывод
Светлая тема Темная тема
Произошла ошибка: FormatException: Invalid radix-10 number (at character 1)
Изучаем HTTP
^
Тип ошибки: FormatException

Объяснение:

Перехват определенных типов исключений

on ExceptionType перехватывает только исключения указанного типа

Можно иметь несколько блоков on

Они обрабатываются сверху вниз

Например

Dart
Светлая тема Темная тема
import 'dart:io';

void main() {
  try {
    // int.parse('Это обычная строка'); // Выбрасывает FormatException
    File('Файла_которого_нет.txt').readAsStringSync(); // Выбрасывает FileSystemException
  } on FormatException catch (e) {
    print('Ошибка формата данных: $e');
  } on FileSystemException catch (e) { // Этот блок не сработает, так как сработал FormatException
    print('Ошибка файловой системы: ${e.message}');
  } catch (e) { // Общий catch для любых других исключений
    print('Произошла общая ошибка: $e');
  } finally {
    print('Завершение попытки.');
  }
}
Вывод
Светлая тема Темная тема
Ошибка файловой системы: Cannot open file
Завершение попытки.

Выбрасывание своих исключений (throw)

Можно выбрасывать (throw) свои собственные исключения, когда в коде возникает ситуация, которую он не может обработать самостоятельно.

Например

Dart
Светлая тема Темная тема
// Создаём свой тип для исключения
class InvalidInputException implements Exception {
  final String message;
  InvalidInputException(this.message);

  @override
  String toString() => 'InvalidInputException: $message';
}

void processInput(String input) {
  if (input.isEmpty) {
    throw InvalidInputException('Пусто и грустно ...');
  }
  if (input.length < 5) {
    throw ArgumentError('Входные данные слишком короткие');
  }
  print('Ок: $input');
}

void main() {
  try {
    processInput(''); // Выбросит InvalidInputException
    // processInput('Ой'); // Выбросит ArgumentError
    // processInput('Привет :)'); // Успешно
  } on InvalidInputException catch (e) {
    print('Ошибка: ${e.message}');
  } on ArgumentError catch (e) {
    print('Ошибка: ${e.message}');
  } catch (e) {
    print('Неизвестная ошибка: $e');
  }
}
Вывод
Светлая тема Темная тема
Результат 

Ошибка: Пусто и грустно ...

Обработка ошибок в асинхронном коде

try-catch блоки используются вокруг await выражений.

Dart
Светлая тема Темная тема
Future fetchData() async {
  await Future.delayed(Duration(seconds: 3)); // Имитация задержки сети
  // Имитация ошибки сети
  throw Exception('Не удалось получить данные с сервера.');
  // return 'Данные успешно получены!';
}

Future processData() async {
  try {
    String data = await fetchData(); // Ожидаем завершения Future
    print('Данные: $data');
  } catch (e) {
    print('Ошибка при обработке данных: $e');
  } finally {
    print('Завершение асинхронной операции.');
  }
}

void main() async {
  print('Начало программы.');
  await processData(); // Ожидаем завершения асинхронной функции
  print('Программа завершена.');
}
Вывод
Светлая тема Темная тема
Результат 

Начало программы.
Ошибка при обработке данных: Exception: Не удалось получить данные с сервера.
Завершение асинхронной операции.
Программа завершена.