Try
Catch
On
Finally
In Dart, exception handling is used to manage errors gracefully and prevent the program from crashing. Dart provides three primary constructs for handling exceptions: try-catch, on, and finally. Here's a detailed explanation with syntax:
The try-catch block is used to handle exceptions. The code that might throw an exception is placed inside the try block, and the catch block handles the exception.
Syntax:
try {
// Code that might throw an exception
} catch (e) {
// Handle the exception
print('Exception caught: $e');
}
Example:
void main() {
try {
int result = 10 ~/ 0; // Division by zero will throw an exception
print('Result: $result');
} catch (e) {
print('Exception caught: $e');
}
}
The on block is used to handle specific types of exceptions. It allows you to catch exceptions of a specific type.
Syntax:
try {
// Code that might throw an exception
} on SpecificExceptionType {
// Handle the specific exception
}
Example:
void main() {
try {
int result = 10 ~/ 0; // Throws IntegerDivisionByZeroException
print('Result: $result');
} on IntegerDivisionByZeroException {
print('Cannot divide by zero!');
}
}
You can use the catch block to capture the exception object and optionally the stack trace.
Syntax:
try {
// Code that might throw an exception
} catch (e, s) {
// e is the exception object
// s is the stack trace
print('Exception: $e');
print('Stack trace: $s');
}
Example:
void main() {
try {
int result = 10 ~/ 0;
print('Result: $result');
} catch (e, s) {
print('Exception caught: $e');
print('Stack trace: $s');
}
}
The finally block is used for code that must run whether an exception is thrown or not. It's typically used for cleanup tasks.
Syntax:
try {
// Code that might throw an exception
} catch (e) {
// Handle the exception
} finally {
// Code that always executes
}
Example:
void main() {
try {
int result = 10 ~/ 0;
print('Result: $result');
} catch (e) {
print('Exception caught: $e');
} finally {
print('This will always execute.');
}
}
You can combine on for specific exceptions and catch for general exceptions.
Syntax:
try {
// Code that might throw an exception
} on SpecificExceptionType {
// Handle specific exception
} catch (e) {
// Handle general exceptions
}
Example:
void main() {
try {
int result = 10 ~/ 0;
print('Result: $result');
} on IntegerDivisionByZeroException {
print('Cannot divide by zero!');
} catch (e) {
print('An exception occurred: $e');
}
}
try-catch: General exception handling.
on: Handles specific types of exceptions.
catch: Captures exception and stack trace.
finally: Executes cleanup code, regardless of exceptions.
Exception handling in Dart allows you to gracefully manage errors and exceptions in your code, ensuring your application behaves predictably even when something goes wrong. Dart provides a structured way to handle exceptions using try, catch, on, and finally blocks.
try {
// Code that might throw an exception
} on SpecificException {
// Handle a specific type of exception
} catch (e, s) {
// Handle any exception
// e: the exception object
// s: the stack trace (optional)
} finally {
// Code that will always execute, regardless of exceptions
}
try Block:
Encapsulates the code that may throw an exception.
on Keyword:
Used to handle a specific type of exception.
catch Keyword:
Handles exceptions that are not explicitly specified.
Can capture the exception (e) and the stack trace (s).
finally Block:
Contains code that will execute regardless of whether an exception is thrown or not (e.g., cleanup actions).
void main() {
try {
int result = 10 ~/ 0; // Division by zero
print(result);
} catch (e) {
print('Exception caught: $e');
} finally {
print('Execution completed.');
}
}
Output:
Exception caught: IntegerDivisionByZeroException
Execution completed.
void main() {
try {
List<int> numbers = [1, 2, 3];
print(numbers[5]); // Accessing an out-of-range index
} on RangeError {
print('RangeError: Index out of bounds!');
} catch (e) {
print('An exception occurred: $e');
}
}
Output:
RangeError: Index out of bounds!
void main() {
try {
File file = File('nonexistent_file.txt');
String content = file.readAsStringSync();
print(content);
} catch (e) {
print('File error: $e');
} finally {
print('Cleaning up resources...');
}
}
Output:
File error: FileSystemException: Cannot open file
Cleaning up resources...
You can define and throw your custom exceptions by creating a class that implements Exception.
class CustomException implements Exception {
final String message;
CustomException(this.message);
@override
String toString() => 'CustomException: $message';
}
void main() {
try {
throw CustomException('This is a custom exception!');
} catch (e) {
print(e);
}
}
Output:
CustomException: This is a custom exception!
Use specific exceptions (on) where possible to improve code clarity.
Use the finally block for tasks that must run regardless of exceptions (e.g., closing a file or database connection).
Avoid overusing generic catch unless necessary, as it may make debugging harder.
void main() {
try {
int result = 10 ~/ 0;
} catch (e) {
print('Caught an exception: $e');
}
}
void main() {
try {
int result = 10 ~/ 0;
} catch (e, s) {
print('Exception: $e');
print('Stack trace: $s');
}
}
void main() {
try {
int result = 10 ~/ 2;
print(result);
} catch (e) {
print('Exception caught: $e');
} finally {
print('This always executes.');
}
}
void main() {
try {
List<int> list = [1, 2, 3];
print(list[5]);
} on RangeError {
print('RangeError: Out of bounds!');
}
}
void main() {
try {
int result = 10 ~/ 0;
} on IntegerDivisionByZeroException {
print('Division by zero!');
} catch (e) {
print('General exception: $e');
}
}
class MyException implements Exception {
final String message;
MyException(this.message);
@override
String toString() => 'MyException: $message';
}
void main() {
try {
throw MyException('This is a custom exception');
} catch (e) {
print(e);
}
}
void main() {
try {
try {
int result = 10 ~/ 0;
} catch (e) {
print('Caught inside inner try: $e');
rethrow; // Re-throws the exception
}
} catch (e) {
print('Caught again: $e');
}
}
void main() {
try {
int result = 10 ~/ 2;
print(result);
} catch (e) {
print('Error: $e');
} finally {
print('Releasing resources...');
}
}
void checkAge(int age) {
if (age < 18) {
throw Exception('Age must be 18 or above.');
}
}
void main() {
try {
checkAge(15);
} catch (e) {
print(e);
}
}
void main() {
try {
int num = 5;
assert(num > 10, 'The number is less than 10.');
} catch (e) {
print('Caught an assertion error: $e');
}
}
void main() {
try {
double result = 10 / 0;
print(result);
} catch (e) {
print('Exception: $e');
}
}
void readFile(String fileName) {
if (fileName != 'valid_file.txt') {
throw Exception('File not found!');
}
}
void main() {
try {
readFile('invalid_file.txt');
} catch (e) {
print(e);
}
}
void main() {
try {
int value = int.parse('abc'); // Invalid integer
} catch (e) {
print('Exception: $e');
}
}
void main() {
String? name;
try {
print(name!.length); // Null safety exception
} catch (e) {
print('Caught a null exception: $e');
}
}
void main() {
int result = 10 ~/ 0; // Unhandled exception, crashes program
print(result);
}
void main() {
for (int i = -2; i <= 2; i++) {
try {
print(10 ~/ i);
} catch (e) {
print('Cannot divide by $i: $e');
}
}
}
Future<void> fetchData() async {
throw Exception('Data not found');
}
void main() async {
try {
await fetchData();
} catch (e) {
print('Async exception: $e');
}
}
Stream<int> getNumbers() async* {
for (int i = 0; i < 5; i++) {
if (i == 3) {
throw Exception('An error occurred at $i');
}
yield i;
}
}
void main() {
getNumbers().listen(
(number) => print(number),
onError: (e) => print('Error: $e'),
);
}
void main() {
try {
try {
throw Exception('Inner exception');
} catch (e) {
print('Caught inner exception: $e');
throw Exception('Outer exception');
}
} catch (e) {
print('Caught outer exception: $e');
}
}
void main() {
try {
dynamic value = 'Hello';
int number = value as int; // Invalid cast
print(number);
} catch (e) {
print('Exception: $e');
}
}