Let's break down exception handling in Dart with clear, human-readable explanations and specific examples.

What is Exception Handling?

Exception handling is a way to manage errors that occur while your program is running. Instead of letting your program crash when an error happens, you can catch these errors (called exceptions) and handle them gracefully.

Key Concepts

  1. Exception: An error that happens at runtime.
  2. Throwing Exceptions: Creating and signaling an error.
  3. Catching Exceptions: Handling the error so your program doesn't crash.
  4. Finally Block: Code that runs no matter what, whether there was an error or not.

Basic Syntax

1. Try-Catch Block

You wrap the code that might throw an error in a try block. If an error occurs, the code inside catch will run.

Example:

void main() {
  try {
    int result = 10 ~/ 0; // Division by zero
    print(result); // This line won't be executed
  } catch (e) {
    print('Caught an exception: $e'); // This will print the error message
  }
}

2. On-Catch Block

You can catch specific types of exceptions using on.

Example:

void main() {
  try {
    List<int> numbers = [1, 2, 3];
    print(numbers[5]); // This will cause an error: index out of bounds
  } on RangeError catch (e) {
    print('Caught a RangeError: $e'); // This will print the specific error message
  }
}

3. Finally Block

The finally block contains code that will run whether or not an exception was thrown.

Example:

void main() {
  try {
    int result = 10 ~/ 0; // Division by zero
    print(result); // This line won't be executed
  } catch (e) {
    print('Caught an exception: $e'); // This will print the error message
  } finally {
    print('This code always runs.'); // This will always be executed
  }
}

4. Throwing Exceptions

You can create your own exceptions using throw.

Example:

void checkValue(int value) {
  if (value < 0) {
    throw Exception('Value cannot be negative'); // Throwing an exception
  }
}

void main() {
  try {
    checkValue(-1); // This will throw an exception
  } catch (e) {
    print('Caught an exception: $e'); // This will catch and print the exception
  }
}

Custom Exceptions

You can define your own exception classes for more specific error handling.

Example:

class NegativeValueException implements Exception {
  final String message;
  NegativeValueException(this.message);
}

void checkValue(int value) {
  if (value < 0) {
    throw NegativeValueException('Value cannot be negative'); // Throwing a custom exception
  }
}

void main() {
  try {
    checkValue(-1); // This will throw the custom exception
  } catch (NegativeValueException e) {
    print('Caught a NegativeValueException: ${e.message}'); // This will catch and print the custom exception message
  }
}

In Short

  • Try: Wraps code that might throw an exception.
  • Catch: Handles the exception.
  • On: Catches specific types of exceptions.
  • Finally: Always runs, whether there was an exception or not.
  • Throw: Creates and signals an error.
  • Custom Exception: Define your own exception classes for specific error handling.