Parsing, I/O and network calls all throw, and catching the right type keeps apps from crashing or hiding bugs.
Dart can throw any non-null object, but by convention you throw:
- `Exception` subtypes for expected, recoverable failures (bad input, network down).
FormatException,IOExceptionandTimeoutExceptionare common built-ins. - `Error` subtypes for programming bugs (
RangeError,StateError,ArgumentError,TypeError). Generally don't catch these; fix the code.
Handling:
try {
final n = int.parse(input);
} on FormatException catch (e) {
print('bad number: ${e.message}');
} catch (e, stackTrace) {
rethrow;
} finally {
cleanup();
}on Type selects by type, catch (e, s) binds the exception and stack trace, and rethrow passes it on unchanged. finally always runs. Order clauses from most specific to most general.
Dart functions don't declare what they throw, so read API docs. Many APIs offer non-throwing variants: int.tryParse returns null instead of throwing.
Define your own exceptions by implementing Exception: class PaymentDeclined implements Exception { ... } with a useful toString.
In async code, errors from awaited futures are caught by the same try/catch. An uncaught exception terminates a command-line program; in Flutter it is reported and the frame continues, but your state may be inconsistent.
Example
class InsufficientFunds implements Exception {
final int missing;
InsufficientFunds(this.missing);
@override String toString() => 'InsufficientFunds: need $missing more';
}
int withdraw(int balance, String input) {
final amount = int.parse(input); // may throw FormatException
if (amount > balance) throw InsufficientFunds(amount - balance);
return balance - amount;
}
void main() {
for (final input in ['30', 'abc', '500']) {
try {
print('left: ${withdraw(100, input)}');
} on FormatException catch (e) {
print('not a number: ${e.source}');
} on InsufficientFunds catch (e) {
print(e);
} finally {
print('done $input');
}
}
// left: 70 / done 30 / not a number: abc / done abc / InsufficientFunds: need 400 more / done 500
print(int.tryParse('x') ?? -1); // -1
}Remember
- Throw
Exceptions for recoverable problems;Errors mean bugs on Type catch (e, s)catches selectively;rethrowpasses it on- Prefer non-throwing variants like
tryParsefor expected bad input
Watch out for
- A bare
catch (e)that swallows everything, including real bugs.