Error Handling

Learn to handle errors gracefully and build robust apps

Error Handling in Dart


What are Exceptions?


Exceptions are errors that occur during program execution. They can be caused by:

  • Invalid operations
  • Missing data
  • Resource unavailability
  • Logic errors

  • Why Handle Errors?


    Error handling allows your program to:

  • Recover from errors gracefully
  • Provide meaningful feedback to users
  • Prevent app crashes
  • Log problems for debugging
  • Continue running despite issues

  • Exception Hierarchy


    `

    Exception

    ├── IOException

    ├── FormatException

    ├── ArgumentError

    ├── StateError

    └── ... (many more)

    `

    Common Exceptions


  • **Exception**: Base class for all Dart exceptions
  • **Error**: Serious problems the app should fix
  • **FormatException**: Invalid data format
  • **ArgumentError**: Invalid argument passed
  • **RangeError**: Value outside expected range
  • **StateError**: Invalid state for operation
  • Cell2Dart
    // Without error handling - CRASHES int divide(int a, int b) { return a ~/ b; // Integer division } // With error handling - SAFE int divideSafe(int a, int b) { if (b == 0) { print('Error: Cannot divide by zero'); return 0; } return a ~/ b; } // Test it print('Safe: ${divideSafe(10, 2)}'); print('Safe: ${divideSafe(10, 0)}');

    Try-Catch Blocks


    The try-catch statement catches exceptions when they occur.


    Syntax


    ``dar

    try {

    // Code that might throw an exception

    riskyOperation();

    } catch (error) {

    // Handle the error

    print('Caught error: $error');

    } finally {

    // Code that always runs (optional)

    cleanup();

    }

    `

    Parts of Try-Catch


    **try**: Contains risky code that might throw an exception


    **catch**: Handles specific exception types

  • Can have multiple catch blocks
  • Catches parameter is optional

  • **finally**: Runs whether exception occurs or not

  • Use for cleanup (closing files, releasing resources)
  • Optional block
  • Cell4Dart
    // Try-catch example class Calculator { int divide(int a, int b) { if (b == 0) { throw Exception('Cannot divide by zero'); } return a ~/ b; } int parseNumber(String value) { try { return int.parse(value); } catch (e) { print('Error parsing: $e'); return 0; } } } // Use it Calculator calc = Calculator(); try { int result = calc.divide(10, 2); print('Result: $result'); int number = calc.parseNumber('123'); print('Number: $number'); } catch (error) { print('Operation failed: $error'); }

    Multiple Catch Blocks


    You can catch different exception types with separate blocks.


    ``dar

    try {

    riskyOperation();

    } on FormatException catch (e) {

    print('Format error: $e');

    } on ArgumentError catch (e) {

    print('Argument error: $e');

    } catch (e) {

    print('Unknown error: $e');

    }

    `

    on vs catch


  • **on**: Catches specific exception type
  • **catch**: Catches any exception

  • **Best Practice**: Be specific with 'on', use 'catch' as fallback


    Throwing Exceptions


    Throw exceptions to signal errors.


    ``dar

    void validateAge(int age) {

    if (age < 0) {

    throw ArgumentError('Age cannot be negative');

    }

    if (age > 150) {

    throw RangeError('Age seems too high');

    }

    }

    `
    Cell6Dart
    // Throwing and catching specific exceptions class User { String name = ''; int age = 0; void setAge(int value) { if (value < 0) { throw ArgumentError('Age cannot be negative'); } if (value > 150) { throw RangeError('Age unrealistic'); } age = value; print('Age set to $age'); } } // Handle different errors User user = User(); try { user.setAge(25); user.setAge(-5); // Will throw } on ArgumentError catch (e) { print('Invalid argument: $e'); } on RangeError catch (e) { print('Out of range: $e'); } catch (e) { print('Unknown error: $e'); }

    Custom Exceptions


    Create your own exception classes for specific situations.


    ``dar

    class InsufficientFundsException implements Exception {

    String message = '';

    InsufficientFundsException(this.message);


    @override

    String toString() => message;

    }


    void withdraw(double amount, double balance) {

    if (amount > balance) {

    throw InsufficientFundsException(

    'Withdrawal of $amount exceeds balance of $balance'

    );

    }

    }

    `

    Error Handling Best Practices


    1. **Be Specific**: Catch specific exceptions, not all

    2. **Clean Up Resources**: Use finally for cleanup

    3. **Log Errors**: Record what went wrong

    4. **Provide Context**: Include relevant information in messages

    5. **Don't Ignore Errors**: Always handle or propagate

    6. **Fail Fast**: Detect errors early

    7. **Test Error Cases**: Write tests for error scenarios

    Run code to see error handling in action