Java

TOPIC i04 – ERROR HANDLING 1

 

 

LESSON NOTE

 

 

INTRO

 

Exceptions are events that occur during program execution that interrupt the normal flow of statements.  For example, if you try to open a file to that doesn’t exist, then the program cannot continue normally. 

 

In this lesson, we will look at exceptions and how to handle them.

 

A FEW COMMON EXCEPTIONS

 

Here are a few exceptions that you have likely seen:

 

  • NullPointerException – Occurs when a program uses a null object where an actual object is required.

  • IndexOutOfBoundsException – Occurs when a program tries to access an array’s element number that doesn’t exist.

  • FileNotFoundException – Occurs when you try to open a file that doesn’t exist in the specified location.

TWO FAMILES OF EXCEPTIONS

 

There are two groups of exceptions – checked exceptions and unchecked exceptions. 

Unchecked errors are runtime exceptions that are usually cannot be recovered from as the code needs to be changed.  Examples include NullPointerException and IndexOutOfBoundsException.  Such exceptions do not need to be handled.

 

Checked errors are exceptions that involve conditions outside of the program such as missing files, lost network connections or invalid input.  Such exceptions must be handled.  Any method whose implementation can cause checked exceptions must handle the exception.

 

All you need to remember here is that some exceptions have to be handled and some don’t.

 

HANDLING EXCEPTIONS

 

There are two ways to handle exceptions:

1)    using a try/catch statement, or

2)    having the method pass that responsibility up the stack to the calling method.

 

TRY/CATCH STRUCTURE

 

The try/catch structure allows us to catch exceptions and offer alternative code that will be executed.

 

The statement(s) that might cause the exception(s) are placed in the try block.  The statements that should be executed when an exception occurs are placed in the catch block.  Here is the general structure:

 

   try

   {

      //statements that might cause an exception go here

   }

   catch (TypeOfException e)

   {

      //statements that deal with exception go here

   }

 

EXAMPLE 1

 

In the example below, the statement a[3]=4; creates an exception.  Normally, we would simply get an error and the program would stop executing. 

 

However, using the try/catch, we can continue running the code. Immediately after the exception, the statement inside the catch block is executed outputting a message.  If the statement in the try was changed to be ‘legal’, then the statement in the catch block would not be executed.

 

   public static void main(String[] args)

   {

        int[] a = {4,5,6};

       

        try

        {

             a[3]=4;   //creates exception

        }

        catch(IndexOutOfBoundsException e)

        {

            System.out.println("Max index number is 2");

        }

   }

 

Note: The exception above does not need to be handled.  Therefore, we can run the program without the try/catch block and if the exception occurs, then the program will simply stop running.

EXAMPLE 2

 

In this example, we will work with file I/O.  Note that unlike example 1, we are forced to handle this type of exception. 

 

The program below will simply open a file and output the content of its first line to screen.  Inside the try block, three of the four statements can actually cause an exception.

 

     public static void main(String[] args)

     {

         BufferedReader br = null;

         try

         {

             br = new BufferedReader(new FileReader("file.txt")); 

             String firstLine = br.readLine();

             System.out.println(firstLine);

             br.close();

         }

         catch (Exception e)

         {

             System.out.println("Error with file.");

         }

     }

 

Note: One issue here is that it’s possible that you open a file, then cause an exception to jump to the catch block and never close the file.  So it would be good to also close the file inside the catch block, however, this would also require its own try/catch block.


MULTIPLE CATCH BLOCKS

One can catch two different types of exceptions inside a single
try block by simply using the structure below:


   try

   {

      //statements that might cause an exception go here

   }

   catch (TypeOfException1 e)

   {

      //statements that deal with exception go here

   }  

   catch (TypeOfException2 e)

   {

      //statements that deal with exception go here

   }

 

THE FINALLY BLOCK

 

After the try/catch block, you can also have a finally block.  The finally block contains statements that are executed automatically whether the try statement created an exception or not.

 

At first glance it might seem that the finally block is useless.  However, in the scenario where the try/catch blocks contain return statements, the finally block can be used to run code before the return is done.

 

The common example is the scenario where a file is open and processed inside a try block.  If a failure occurs, then we deal with that in the catch block.  However, either way, we need to close the file so we put that code inside the finally block.

 

PASSING THE EXCEPTION UP THE STACK

 

Alternatively to dealing with the exception immediately, we can pass the exception handling responsibility up the call stack.  To do this, in the method’s declaration, we simply use the following:

 

public static int methodName() throws TypeOfException

 

By doing the above, any method that calls methodName() will have to deal with the exception.  Of course, that method can choose to use a try/catch block or again pass that responsibility  along up the stack.

 

EXAMPLE 1

 

The File IO example from above can be written without a try/catch block if we make the method containing it throw an Exception.  Once passed above the main method(), the program will stop running.

 

   public static void main(String[] args) throws Exception

   {

      BufferedReader br = new BufferedReader(new FileReader("f.txt"));

      String firstLine = br.readLine();

      System.out.println(firstLine);

      br.close();

   }

EXAMPLE 2

 

In the example below, we have three methods.  The main method calls fun and fun calls superFun.  The superFun method can create an exception but instead of dealing with it there with a try/catch, it sends that responsibility to the method that called it (fun method).  In turn, fun also sends that responsibility to the method thatcalled it (main method).  The main method deals with the exception using a try/catch structure. 

 

public class PassingTheBuck

{

   public static void main(String[] args)

   {

        try

        {

           fun();

        }

        catch (Exception e)

        {

             System.out.println("There were problems.");

        }

   }

 

   public static void fun() throws Exception

   {

        superFun();

   }

    

   public static void superFun() throws Exception

   {

         BufferedReader br = new BufferedReader(new FileReader("f.txt"));

        String firstLine = br.readLine();

        System.out.println(firstLine);

        br.close();

   }

}