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

Что выбрасывает программа когда происходит crash?

3.0 Senior🔥 81 комментариев
#Архитектура Flutter#Нативная интеграция#Тестирование

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

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

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

Исключения при crash программы в Dart/Flutter

Когда происходит crash в программе на Dart, выбрасываются исключения (exceptions). Рассмотрим типы исключений и механизм их обработки.

Основные типы исключений

Exception — базовый класс

// Exception — все исключения наследуют от этого класса
class CustomException implements Exception {
  final String message;
  CustomException(this.message);
  
  @override
  String toString() => 'CustomException: $message';
}

Error — критические ошибки (редко ловят)

// Error — более серьезные ошибки (StackOverflowError, OutOfMemoryError)
// Обычно НЕ ловят, т.к. это признак серьезной проблемы

try {
  // Код, который может выбросить ошибку
} on StackOverflowError catch (e) {
  print('Stack overflow: $e');
}

Встроенные исключения Dart

ArgumentError — неправильный аргумент

void processAge(int age) {
  if (age < 0) {
    throw ArgumentError('Age must be positive');
  }
}

// Использование
try {
  processAge(-5);
} on ArgumentError catch (e) {
  print('Argument error: ${e.message}');
}

FormatException — ошибка формата

void parseJson(String json) {
  try {
    final data = jsonDecode(json);
  } on FormatException catch (e) {
    print('Format error: ${e.message}');
  }
}

// Пример
parseJson('{invalid json}'); // FormatException

UnsupportedError — неподдерживаемая операция

class ReadOnlyList<T> {
  final List<T> _items;
  
  ReadOnlyList(this._items);
  
  void add(T item) {
    throw UnsupportedError('Cannot add to read-only list');
  }
}

RangeError — индекс вне диапазона

List<int> numbers = [1, 2, 3];

try {
  print(numbers[10]); // RangeError
} on RangeError catch (e) {
  print('Range error: $e');
}

NoSuchMethodError — метод не найден

Object obj = "hello";

try {
  obj.nonExistentMethod(); // NoSuchMethodError
} on NoSuchMethodError catch (e) {
  print('Method not found: $e');
}

NullPointerException (теоретически)

Благодаря null safety в Dart, NullPointerException не выбрасывается:

String? name = null;
// name.length; // Ошибка компиляции, не runtime!

// Вместо этого используем проверку:
if (name != null) {
  print(name.length);
}

Иерархия исключений Dart

Object
├── Exception (обычные исключения)
│   ├── FormatException
│   ├── ArgumentError
│   ├── UnsupportedError
│   ├── RangeError
│   └── (custom exceptions)
└── Error (критические ошибки)
    ├── AssertionError
    ├── OutOfMemoryError
    ├── StackOverflowError
    └── UnsupportedError

Обработка исключений

Try-catch

Future<void> fetchData() async {
  try {
    final response = await http.get(Uri.parse('api.example.com'));
    if (response.statusCode != 200) {
      throw Exception('Failed to load data');
    }
  } on SocketException {
    print('Network error');
  } on TimeoutException {
    print('Request timeout');
  } on FormatException {
    print('Invalid response format');
  } catch (e) {
    print('Unknown error: $e');
  }
}

Try-catch-finally

File file;

try {
  file = File('data.txt');
  final content = file.readAsStringSync();
  print('Content: $content');
} on FileSystemException catch (e) {
  print('File error: ${e.message}');
} finally {
  // Выполнится в любом случае
  print('Operation completed');
}

Кастомные исключения

// Базовое кастомное исключение
class AppException implements Exception {
  final String message;
  final String? code;
  final dynamic originalException;
  
  AppException({
    required this.message,
    this.code,
    this.originalException,
  });
  
  @override
  String toString() => 'AppException: $message (code: $code)';
}

// Специфичные исключения
class ApiException extends AppException {
  final int? statusCode;
  
  ApiException({
    required String message,
    this.statusCode,
    String? code,
    dynamic originalException,
  }) : super(
    message: message,
    code: code,
    originalException: originalException,
  );
}

class AuthException extends AppException {
  AuthException(String message)
      : super(
        message: message,
        code: 'AUTH_ERROR',
      );
}

class ValidationException extends AppException {
  final Map<String, String> errors;
  
  ValidationException({
    required this.errors,
    String message = 'Validation failed',
  }) : super(message: message, code: 'VALIDATION_ERROR');
}

Практический пример обработки

Future<User> fetchUser(String userId) async {
  try {
    final response = await http.get(
      Uri.parse('api.example.com/users/$userId'),
    ).timeout(Duration(seconds: 10));
    
    if (response.statusCode == 401) {
      throw AuthException('Unauthorized');
    }
    
    if (response.statusCode == 404) {
      throw ApiException(
        message: 'User not found',
        statusCode: 404,
      );
    }
    
    if (response.statusCode != 200) {
      throw ApiException(
        message: 'Failed to fetch user',
        statusCode: response.statusCode,
      );
    }
    
    return User.fromJson(jsonDecode(response.body));
    
  } on TimeoutException {
    throw ApiException(
      message: 'Request timeout',
      code: 'TIMEOUT',
    );
  } on SocketException {
    throw ApiException(
      message: 'Network error',
      code: 'NETWORK_ERROR',
    );
  } catch (e) {
    throw ApiException(
      message: 'Unexpected error',
      originalException: e,
    );
  }
}

Обработка в Flutter виджетах

class UserScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FutureBuilder<User>(
      future: fetchUser('123'),
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          final error = snapshot.error;
          
          if (error is AuthException) {
            return Center(
              child: Text('Please log in again'),
            );
          } else if (error is ApiException) {
            return Center(
              child: Text('API Error: ${error.message}'),
            );
          } else {
            return Center(
              child: Text('Unknown error: $error'),
            );
          }
        }
        
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        }
        
        final user = snapshot.data!;
        return UserProfile(user: user);
      },
    );
  }
}

Global Error Handling

void main() {
  // Ловить необработанные исключения
  FlutterError.onError = (FlutterErrorDetails details) {
    print('Flutter Error: ${details.exceptionAsString()}');
    // Логировать на сервер
    logErrorToServer(details);
  };
  
  // Ловить ошибки вне Flutter фреймворка
  PlatformDispatcher.instance.onError = (error, stack) {
    print('Platform Error: $error');
    // Логировать на сервер
    logErrorToServer(error.toString(), stack);
    return true;
  };
  
  runApp(MyApp());
}

Итого

Quando программа crashит, выбрасываются:

  • Exception — обычные исключения (ArgumentError, FormatException, RangeError)
  • Error — критические ошибки (StackOverflowError, OutOfMemoryError)
  • Custom exceptions — кастомные исключения для бизнес-логики

Ключевые моменты:

  • Всегда ловить и обрабатывать исключения
  • Использовать специфичные типы исключений
  • Создавать кастомные исключения для разных типов ошибок
  • Не ловить Error (только в исключительных случаях)
  • Логировать ошибки для отладки и мониторинга