Java Exception Handling

Let’s look at Java exception handling. It is one of the most useful topics and can be confusing at times. But Java exceptions are pretty simple to understand and here we will try to cover most of Java exception handling.
Some Questions:

  1. Why do we need exception handling in Java?
  2. Differences between checked and unchecked exceptions in Java?
  3. How and when to use “throws” and “throw” keywords?

By understanding Java exception handling, we can make our programs terminate more gracefully when errors occur in our program both due to programmatic errors and unforeseen errors. The exceptions could range from a simple NullPointerException, IndexOutOfBoundsException, IOException, FileNotFoundException, OutOfMemoryError,etc.

Lets start with the basics of Try-Catch block.

import java.io.File;
  import java.util.Scanner;

  public class JavaException {

      /**
       * @param args
       */
     public static void main(String[] args) {
        String filename = "/Users/test.txt";

        File textFile = new File(filename);
        Scanner in = new Scanner(textFile);

        while(in.hasNext()) {
           String line = in.nextLine();
           System.out.println(line);
         }

         in.close();
      }

  }

This program won’t compile in Java without proper exception handling. But for now, assume that this code compiles. If we look closely, as a user several questions may come to our mind on what if the file doesn’t exist at all?. The program will crash and prints out an exception trace. An end user who doesn’t know the technical details of Java doesn’t like to see an exception being printed to him. But rather would like a more elegant way of being informed of errors and exceptions from the application. So we will see if by adding try-catch blocks, we can achieve our objectives.

String filename = "/Users/test.txt";
      try {
           File textFile = new File(filename);
           Scanner in = new Scanner(textFile);

           while(in.hasNext()) {
                 String line = in.nextLine();
                 System.out.println(line);
           }

           in.close();
       } catch (Exception e) {
                  System.out.println("Sorry! File Not Found");
       }

We surround the code with try-catch block like the one shown above where the exceptions are likely to occur. This program is better than the previous one as the user would only see the message “Sorry! File Not Found!” error instead of any stack trace. We can internally print a stack trace to a file or server for the Java developers to debug the issue rather than displaying the stack trace to the user.

Are we done? No. There are some flaws in the above program. Remember that a file is not found, and then program doesn’t continue execution beyond the Scanner line. Why? Because Java couldn’t locate the file and so threw an exception and the next execution jumps to the Catch block and prints the error message. If we notice carefully, we haven’t executed the line, in.close() which closes the input stream which is not desirable. Of course, we can close this in the Catch block but Java has a separate block called “Finally”, which is generally used to do resources cleanup code.

String filename = "/Users/test.txt";
      File textFile = null;
      Scanner in = null;

      try {
            textFile = new File(filename);
            in = new Scanner(textFile);
            while(in.hasNext()) {
                  String line = in.nextLine();
                  System.out.println(line);
            }

       } catch (Exception e) {
            System.out.println("Sorry! File Not Found");
       }
       finally {
            in.close();
       }

I just added a finally block of code to make sure that the input stream if exception occurs or doesn’t occur. So remember that code under finally block is always executed irrespective of whether an exception occurs or not in try block. But if an exception occurs, further statements in the try block are not executed and both Catch, Finally block of code is executed. Lets go a step further.

Java Exception Hierarchy

Just like every object in java extends Object class, all exception classes extend Throwable by default as it is under java.lang package. There is a hierarchy to the Java exceptions. Here is a simple chart to explain the exception hierarchy.

Exception Hierachy

The hierarchy is pretty simple.

  • When errors occur, programmers needn’t handle them but rather the JVM does that for us. Why? Because they could occur because of reasons beyond the control of programmers. Errors like OutOfMemoryError fall under that category. Developers needn’t handle them explicitly whereas some types of exception need to be explicitly handled by developers.
  • Unchecked or runtime exceptions generally occur because of bad programming. For example, accessing null values, divide by zero error, accessing array values beyond the array length, which are some instances of bad programming. It is upto Java programmers to either handle it or JVM does that for us. Hence Java doesn’t enforce RunTimeExceptions during compile time and it is left to developer’s choice.
  • But Checked exceptions are those that Java developers are expected to handle in their code. Because these checked exceptions occur because of invalid inputs/conditions provided generally beyond the program’s control. File not found in the path provided by user, user providing wrong parameters to a SQL are such instances. Java checks for these exceptions at compile time and so Java developers should handle them appropriately in their code. We will see some examples below to illustrate the differences.

Throws Keyword

If we know that Checked exception that can occur, Java will checks this at compile time if they have been handled properly. So Java developers need to either handle checked exceptions with try-catch block or use “throws” keyword to throw that checked exception back to the program that called this method.

public static void main(String[] args) {
          String filename = "/Users/test.txt";
          try {
               handleFile(filename);
          } catch (FileNotFoundException e) {
              System.out.println(“Error in file”);
          }
     }

     public static void handleFile(String fileName) throws FileNotFoundException {
        File textFile = null;
        Scanner in = null;
        textFile = new File(fileName);
        in = new Scanner(textFile);
        while(in.hasNext()) {
            String line = in.nextLine();
             System.out.println(line);
        }
      }

I have modified my earlier program to illustrate “throws” keyword. Since FileNotFoundException is a checked exception, we need to handle it either with try-catch or throw that exception to main() program which called this method. I have decided to throw the exception back to the caller and so I have used “throws” keyword to throw this checked exception back to main(). The calling method needs to know that this handleFile() method throws a checked exception and so this has to be explicitly used as part of method definition. Java forces only Checked Exceptions to be handled and hence I have used public static void handleFile(String fileName) throws FileNotFoundException. main() must handle that FileNotFoundException and hence a try-catch block surrounds that because main() is the starting point of my program in my case and so will be handling all exceptions.

Throw Keyword

public static void main(String[] args) {
        String filename = "/Users/test.txt";
        try {
             handleFile(filename);
        } catch (IOException e) {
             e.printStackTrace();
        }
   }

   public static void handleFile(String fileName) throws IOException {
        // some logic for processing …..
        throw new IOException("File Not Found");
    }

Suppose we decide that we need to raise some exceptions based on certain failures occurring in our applications. In such cases, we use the “throw” keyword to throw the exception of our case. This exception can be either checked/unchecked exceptions using “throw” keyword. Again, if it is a checked exception, this exception can be thrown back to main() method or use try-catch block to handle this thrown exception.

Catch Blocks Hierachy

String filename = "/Users/test.txt";

try {
   handleFile(filename);
} catch (IOException e) {
     System.out.println(“IOException”);
} catch (FileNotFoundException e) {
     System.out.println(“File not found”);
}

One more thing in catch blocks is the hierarchical nature of exceptions. In the above case, FileNotFoundException extends IOException which means that all FileNotFoundExceptions are all IOExceptions but not vice-versa as there could be several other classes which also extend Java IOException. IOException is the parent class. Hence the above code will not compile as the first catch block will catch all IOExceptions including FileNotFoundException and so the second class will never be reached by any Java code. The correct form of hierarchy is:

try {
          handleFile(filename);
     } catch (FileNotFoundException e) {
          e.printStackTrace();
     } catch (IOException e) {
          e.printStackTrace();
     }

If there is a FileNotFoundException error, Java matches the first catch block and executes that. But if any other IOException occurs (excluding FileNotFoundException), Java matches the second catch block. So remember that the parent Exception class should be always at the bottom, so that if none of the exceptions match, the parent class Exception will handle the exception.

Java Exception Wrapping

Having looked at “throw”, “throws” keywords usage, lets look at this example.

public static void handleFile(File file) throws FileNotFoundException,EOFException {
       if (!file.exists())
            throw new FileNotFoundException("Invalid file");
       if (file.canRead())
            throw new EOFException("End of file");
       }
  }

This example looks good first but what if some other method throws ten different exceptions. Do we use 10 different “throws” in method definition? Of course we could but it doesn’t look good as it looks clumsy and code becomes unreadable as more checked exceptions are added to that method. There is a much cleaner way to do this and that is using Java exception wrapping.

All we do is to wrap exceptions in another exception and then throw only that one exception instead of ‘n’ number of exception. We have catch block for all checked exceptions and then use a custom exception to inform the caller of any exceptions. So now, we have only one “throws” exception, which makes the code look much cleaner and understandable. For example,

public static void handleFile(File file) throws CustomException {
        try {
             if (!file.exists())
                 throw new FileNotFoundException("Invalid file");
             else if (!file.read())
                  throw new EOFException("File doesn't exist");
         } catch (FileNotFoundException e) {
               throw new CustomException("File Not found");
         } catch (EOFException e) {
               throw new CustomException("EOF found");
         } catch (IOException e){
               throw new CustomException("IO Exception occured");
         }

     }

Of course, this is not a compulsion. Based on requirements, these can be modified accordingly.

Custom Exception Class

Having looked at Java in build exceptions until this point, lets create a sample custom exception class. An exception class can either extend RunTimeException if it has to be a runtime exception or Exception if it has to be case checked exceptions. Checked exceptions will be checked at compiler stage and so a method throwing this custom checked exception has to either use “throws” keyword to throw the exception back to caller or handler the exception with a try-catch block. Always remember this golden rule. So based on design needs, choose the parent Exception class.

public class CustomException extends RuntimeException{

       private static final long serialVersionUID = 1L;

       /**
        * @param args
        */
       public CustomException() {
              super();
       }

       public CustomException(String msg) {
              System.out.println("Custom Exception called");
       }

       public String getMessage() {
              return super.getMessage();
       }

   }

A straightforward implementation of CustomException class. It extends RunTimeException and overrides some of the methods that are required.

Summary

That’s it about exceptions for now. Hope you enjoyed reading the article and learned more about exceptions before you began reading this. You will learn more once you start writing programs in Java. So start incorporating exception handling in your Java code from now and post your comments.

This article is originally published at Java tutorials – Lets jump into the ocean, re-posted here with authors permission and as part of the JBC program.

Comments

comments

About Rengasudharsan Srinivasan

Renga is currently working as a software engineer. He has experience developing web applications using spring, struts and Hibernate framework. He is passionate about learning new technologies and has recently started writing a blog http://renga86.blogspot.com mainly focussing on Java.

Speak Your Mind

*