DMarlon Studio

Lesson 18 · 18 of 20

Exceptions · Dart

Handle errors in Dart with try, on, catch and finally, and raise your own with throw: a cash machine that refuses negative amounts and overdrafts.

Dart · Exceptions in DMarlon Studio: the example's code and its output in the terminal

When something goes wrong, Dart throws an exception and, if nobody handles it, the program stops. `try` marks the code that might fail and `on FormatException` handles that kind of error: int.parse('forty') fails, the warning is printed and the loop carries on as normal.

`throw` raises an exception of your own when something is not allowed. withdraw throws an `ArgumentError` if the amount is not positive and a `StateError` if there is not enough money; either way it never reaches return, so balance does not change.

A try can have several branches, which Dart tries in order. `on ArgumentError catch (e)` handles that type and keeps the error in e, whose message is the text given to throw. A `catch (e)` without on handles any other error: the StateError is printed in full as Bad state: not enough money.

`finally` always runs, error or not, which is why every operation ends with its checked line. It is the place for anything that must happen no matter what, such as closing a file.

In the end the balance is 70.0: only the first withdrawal worked, and the other two were refused without stopping the program.

Code · main.dart

// throw raises an error when something is not allowed.double withdraw(double balance, double amount) {  if (amount <= 0) throw ArgumentError('the amount must be positive');  if (amount > balance) throw StateError('not enough money');  return balance - amount;}void main() {  // int.parse fails with a FormatException on bad text.  for (var text in ['42', 'forty']) {    try {      print('Read: ${int.parse(text)}');    } on FormatException {      print('"$text" is not a number');    }  }  // on catches one type of error; catch (e) gives the error itself.  double balance = 100;  for (var amount in [30.0, -5.0, 500.0]) {    try {      balance = withdraw(balance, amount);      print('Took out $amount, balance $balance');    } on ArgumentError catch (e) {      print('Refused: ${e.message}');    } catch (e) {      print('Error: $e');    } finally {      // finally always runs, with or without an error.      print('  operation of $amount checked');    }  }  print('Final balance: $balance');}

Output · dart run main.dart

Read: 42
"forty" is not a number
Took out 30.0, balance 70.0
  operation of 30.0 checked
Refused: the amount must be positive
  operation of -5.0 checked
Error: Bad state: not enough money
  operation of 500.0 checked
Final balance: 70.0

Key points

  • try { } wraps the code that might fail.
  • on Type handles one kind of error; catch (e) gives you the error.
  • throw ArgumentError('...') raises your own error.
  • finally always runs.
  • A handled error does not stop the program.

Exercise

Add a deposit function that throws an ArgumentError when the amount is over 1000, and try it inside a try with three amounts, one of them 2000.