Throwing and Catching Exceptions

We already used exceptions in some of the previous chapters, but we’ll go through the Flutter implementation in more detail in this section.

Exceptions are used in a piece of code as a way to signal that something’s gone wrong, the current function(or Anonymous Functions and Closures)’s execution is interrupted and the calling function is supposed to deal with it by catching it.

Throwing an Exception

In Dart exceptions are thrown using the throw keyword ( in Python you’d call this raising an exception, in case you never got to see what the world looks like outside of Python). You can create your own exception by creating a class that Writing a Class That implements an Interface the Exception class error:

 class​ MyOwnPersonalException ​implements​ Exception {
  MyOwnPersonalException(​this​.myOwnPersonalMember);
 
 String​ myOwnPersonalMember;
 }
 
 double​ ​myPersonalDivision​(​double​ a, ​double​ b) {
 if​(b == 0) {
 throw​ MyOwnPersonalException(​"Failed to divide a number by 0."​);
  }
 return​ a/b;
 }

Catching an Exception

Whenever we call a function or use an operation that may fail under certain circumstances we’re not checking for, we should be catching the exception:

 void​ ​responsibleFunction​() {
 int​ a, b;
 // ...
  b = 0;
 try​ {
 int​ d = myPersonalDivision(a, b);
 // ...
  }
 catch​(exception) {
 // Deal with the exception
  }
 // ...
 }

You can substitute exception in catch’s parentheses with whatever you want (it is usually just e). It contains the name of the exception that was thrown. You can print it to the debug console by using print(exception). Additionally, you can pass a stack trace of the source of the error, which you can also print.

For example, the following:

 try​ {
 int​.parse(​"Flutter"​);
 } ​catch​(e, stacktrace) {
  print(e);
  print(stacktrace);
 }

will trigger a FormatException and print the following to the debug console:

 FormatException: Invalid radix-10 number (at character 1)
 Flutter
 ^
 #0 int._throwFormatException (dart:core/runtime/lib/integers_patch.dart:131:5)
 #1 int._parseRadix (dart:core/runtime/lib/integers_patch.dart:142:16)
 #2 int._parse (dart:core/runtime/lib/integers_patch.dart:100:12)
 #3 int.parse (dart:core/runtime/lib/integers_patch.dart:63:12)
 #4 main (file:///home/carmine/flutter/example_app/lib/main.dart:21:9)

on SomeException catch()

What if that called function had thrown another kind of exception, which didn’t have myOwnPersonalMember or maybe you needed to deal with different exceptions in different ways? That’s what on is for.

For example, let’s say we have a function that takes two numbers in a string format, parses them, and performs integer division on them. This means two different kinds exceptions can be thrown during its execution: a FormatException if it can’t parse the numbers, or a IntegerDivisionByZeroException exception if we try to divide by zero.

Dart by default performs floating-point division and returns a double number. To perform integer division we need to use the ~/ operator instead of just /. This means the function definition will be the following:

 int​ ​jsonDivide​(​String​ a, ​String​ b) =>
 int​.parse(a)~/​int​.parse(b);

Seen like that, it’s no wonder why a function like this is a good example: it is very short but it could throw two different kinds of exceptions: for example, calling it as jsonDivide("5", "0") will return an IntegerDivisionByZeroException, whereas calling it as jsonDivide("Flutter", "10") will return a FormatException. Let’s pretend we need to tell the user to correct the bad data they entered, so we need to handle each exception differently, which isn’t to hard to do in Dart:

 try​ {
  jsonDivide(firstString, secondString);
 }
 on IntegerDivisionByZeroException {
 // tell the user to not divide by 0
 }
 on FormatException {
 // tell the user to insert valid numbers
 }

So that each of the two on blocks will be executed only when the corresponding exception is thrown.

An alternative syntax for on blocks is on ExceptionName catch(e) {}, which will pass the exception to the block, just like what happens in regular catch blocks.

You can, optionally, add a catch block after the on blocks to handle any exceptions that aren’t handled by the on blocks.

Finally

When using a regular try-catch construct without throwing new exceptions in the process, the execution will continue by executing the instructions placed after the end of the catch block, but if you are only using on blocks instead of generic catch blocks or you’re throwing new exceptions inside catch blocks, the execution will be interrupted and those instructions won’t be executed. If, instead, you want to execute some instructions regardless of anything that happens in the try block and in the catch and on block, you’d use a finally block:

 try​ {
 // code that could fail
 }
 on SomeException {
 // handle SomeExceptin
 }
 finally​ {
 // code that will surely be executed
 }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset