Exception Handling in Dart

In programming world, exception is something unexpected event occurs during the execution of program. Like, performing an operation on null object or trying to open file which doesn’t exist. Exceptions may disrupt the flow of a program and produce unwanted output.  These kind of errors can’t be predetermined. So, exception handling is a way to prevent stopping program abruptly and handle errors gracefully. Let’s see how can we implement in Dart.

With following key concepts, we can implement exception handling:

  1. try
  2. on
  3. catch
  4. finally
try {
        // error-prone code, code which may throw an exception or error
    } on FormatException {
        // Handles only specific kind of exceptions like FormatException
    } on Exception catch (e) {
        // Handle Exception, e can be Exception or subtype of it
    } catch (e, s) {
        // e: exception type
        // s: stacktrace
        // handles rest of the everything
    } finally {
        // will execute irrespective of exception is thrown or not
    }

Let’s understand above code snippet step by step.

try block

Any suspicious or error-prone code should go in try block. So, Dart VM knows that code inside try block may throw an exception. E.g. Network call, File operation, Database operation or anything that we can’t determine prior like third-party libraries behavior. Try block must needs to be followed up by any of on, catch and finally block otherwise compiler gives you the error.

on block & on with catch(e)

When you need to handle any specific exception or subtype of that exception then on block can be used. On with catch(e), it can give the handler the type of an exception for more information.

only catch(e) block

It handles everything which not specified earlier via on block. It can be anything Exception, Error or any Non-null object (Will see it later in this article). catch block can have two parameters, the first one is exception and the second one is stacktrace

finally block

Irrespective of exception is thrown or not, handle or not, code in finally block will execute no matter what (except machine shut-down)! We can write code which needs to be executed  e.g. Resource clean-up, Closing file, Closing network connection, Closing DB operation etc. Program executes in the following sequence:

  1. try block (partially or entirely based on exception occurs or not respectively)/li>
  2. on block (if any)
  3. catch block (if any)
  4. finally block

If the exception is not handled/catched, then isolate (thread of Dart) in which exception occurs will terminate.

Now, let’s say when you have multiple catch blocks then you need to put parent exception catch block last. Following example will show compiler warning:

                            
    void main() {
        try {
            // get int from string
        } on Exception {
            print("Exception");
        } on FormatException { // dead code
            print("FormatException"); 
        }
    }
                            
                        

Here, FormatException is subtype of Exception. So, any FormatException will be catched by Exception block only. on FormatException block is unreachable code or dead code. No FormatException will reach to it. That’s why we need to put parent exception catch block last to handle exceptions.

There are two another important concepts in exceptions:

  1. throw
  2. rethrow
throw keyword

If you want to throw any kind of error or exception then use throw keyword. However, in Dart, we can throw Error, Exception or any other non-null object.

                            
    void main() {
        try {
            double result = performDivideOperation(5, 0);
            print(result);
        } catch (e) {
            print(e);
        }
    }
        
    double performDivideOperation(int dividend, int divisor) {
        if (divisor == 0) {
            throw "Divisor can't be 0"; // throwing string object as an error
        }
        
        return dividend / divisor;
    }
                            
                        

Here, if divisor is 0 then we are throwing a string object as an error. Like string, we can throw any non-null object. But, we should only prefer using Exception or Error class or subclass of it to throw as errors in unexpected scenarios.

rethrow keyword

When you want to partially handle the exception and also want to delegate it then rethrow can be used. Let’s say you have created networking library. For performance and analytical purpose, you want to handle all HttpExceptions and JsonParsingExceptions. But, you are not sure how your users want to handle these kind of errors. So in this scenario, you can use rethrow keyword. Simple example of it:

                            
    void main(List args) {
        try {
            fetchBitcoinPrice();
        } catch (e) {
            print(e);
            // show an error
        }
    }
        
    void fetchBitcoinPrice() {
        try {
            // calling an api to get bitcoin price
            // parsing a response
        } on HttpException catch (e) {
            // handling HttpException
            print(e);
            rethrow;
        } on JsonParsingException catch (e) {
            // handling JsonParsingException
            print(e);
            rethrow;
        }
    }
                            
                        

If you are coming from Java background then Dart has all unchecked exceptions. So, method doesn’t need to tell that it will throw this exception or we don’t need to catch any exception.

Thanks for reading! Please share this article with others to spread knowledge.

Leave a Reply

Your email address will not be published. Required fields are marked *