Thursday 20 July 2017

Exception Handling


What is an exception?

An Exception can be anything which interrupts the normal flow of the program. When an exception occurs program processing gets terminated and doesn’t continue further. In such cases we get a system generated error message. The good thing about exceptions is that they can be handled. We will cover the handling part later in this same tutorial.

Exception can occur at runtime (known as runtime exceptions or Unchecked Exception) as well as at compile-time (known Compile-time exceptions or Checked Exceptions).

Reasons for Exceptions:

There can be several reasons for an exception. For example, following situations can cause an exception – Opening a non-existing file, Network connection problem, Operands being manipulated are out of prescribed ranges, class file missing which was supposed to be loaded and so on.

Advantages of Exception Handling:

Exception handling allows us to control the normal flow of the program by using exception handling in program. It throws an exception whenever a calling method encounters an error providing that the calling method takes care of that error.

It also gives us the scope of organizing and differentiating between different error types using a separate block of codes. This is done with the help of try-catch blocks.

Why to handle exception?

If an exception is raised, which has not been handled by programmer then program execution can get terminated and system prints a non user friendly error message.

Ex:-Take a look at the below system generated exception.

An exception generated by the system is given below Exception in thread "main" 
java.lang.ArithmeticException: / by zero at ExceptionDemo.main(ExceptionDemo.java:5)
ExceptionDemo : The class name main : The method name ExceptionDemo.java : 
The filename java:5 : Line number

For a novice user the above message won’t be easy to understand. In order to let them know that what went wrong we use exception handling in java program. We handle such conditions and then prints a user friendly warning message to user, which lets them correct the error as most of the time exception occurs due to bad data provided by user.

Types of exceptions

There are two types of exceptions
  1. Checked exceptions
  2. Unchecked exceptions
Checked exceptions:

All exceptions other than Runtime Exceptions are known as Checked exceptions as the compiler checks them during compilation to see whether the programmer has handled them or not. If these exceptions are not handled/declared in the program, it will give compilation error.


Examples of Checked Exceptions,
  • ClassNotFoundException
  • IllegalAccessException
  • NoSuchFieldException
  • EOFException etc.

Unchecked Exceptions:

Runtime Exceptions are also known as Unchecked Exceptions as the compiler do not check whether the programmer has handled them or not but it’s the duty of the programmer to handle these exceptions and provide a safe exit.


These exceptions need not be included in any method’s throws list because compiler does not check to see if a method handles or throws these exceptions.

Examples of Unchecked Exceptions:
  • ArithmeticException
  • ArrayIndexOutOfBoundsException
  • NullPointerException
  • NegativeArraySizeException etc.

Exception hierarchy:


Exception handling in Java:

Exceptions can be handled in 2 different ways.
  • try-catch
  • throw 
  • throws
There is a huge difference between these 2 methods- the latter swallows the exception (showing it, admittedly), whereas the first one will let it propagate.
So if you call the first method and "do something" fails, then the caller will have to handle the exception and it can be raw exception which may be easily understandable. If you call the second method and "do something" fails, then the caller may or may not see an exception. But the good thing about it is you can handle it in nice manner and throw meaningful exception that the caller understands it. If you will not throw the caught exception then caller cannot see this exception at all.
Let's explore more about these exception handling types.

Throwing Exceptions ( throw ):

If a method needs to be able to throw an exception, it has to declare the exception(s) thrown in the method signature, and then include a throw-statement in the method. 

Here is an example: 

  public void divide(int numberToDivide, int numberToDivideBy) throws BadNumberException {
    if (numberToDivideBy == 0) {
      throw new BadNumberException("Cannot divide by 0");
    }
    return numberToDivide / numberToDivideBy;
  }

When an exception is thrown the method stops execution right after the "throw" statement. Any statements following the "throw" statement are not executed. In the example above the "return numberToDivide / numberToDivideBy;" statement is not executed if a BadNumberException is thrown. The program resumes execution when the exception is caught somewhere by a "catch" block. Catching exceptions is explained later.

You can throw any type of exception from your code, as long as your method signature declares it. You can also make up your own exceptions. Exceptions are regular Java classes that extends java.lang.Exception, or any of the other built-in exception classes. If a method declares that it throws an exception A, then it is also legal to throw subclasses of A.

Catching Exceptions (try-catch ):

If a method calls another method that throws checked exceptions, the calling method is forced to either pass the exception on, or catch it. Catching the exception is done using a try-catch block.

Here is an example:

public void callDivide() {
 try {
  int result = divide(2, 1);
  System.out.println(result);
 } catch(BadNumberException e) { //do something clever with the exception 
  System.out.println(e.getMessage());

 }
 System.out.println("Division attempt done");
}

The BadNumberException parameter e inside the catch-clause points to the exception thrown from the divide method, if an exception is thrown.

If no exception is thrown by any of the methods called or statements executed inside the try-block, the catch-block is simply ignored. It will not be executed.

If an exception is thrown inside the try-block, for instance from the divide method, the program flow of the calling method, callDivide, is interrupted just like the program flow inside divide. The program flow resumes at a catch-block in the call stack that can catch the thrown exception. In the example above the "System.out.println(result);" statement will not get executed if an exception is thrown fromt the divide method. Instead program execution will resume inside the "catch (BadNumberException e) { }" block.

If an exception is thrown inside the catch-block and that exception is not caught, the catch-block is interrupted just like the try-block would have been.

When the catch block is finished the program continues with any statements following the catch block. In the example above the "System.out.println("Division attempt done");" statement will always get executed.


Propagating Exceptions ( throws ):

You don't have to catch exceptions thrown from other methods. If you cannot do anything about the exception where the method throwing it is called, you can just let the method propagate the exception up the call stack to the method that called this method. If you do so the method calling the method that throws the exception must also declare to throw the exception.

For example if you are trying to read a file with FileReader class, it will ask you to handle FileNotFoundException. It propagate this exception you have to throw it like below,

public void readFile() throws FileNotFoundException  {
    FileReader reader = new FileReader("C:\\temp\\file.txt");
    System.out.println("Reading the file");
}

The program execution is interrupted if the file is not really found in the specified location in the filesystem. is thrown from the divide method. Thus the "System.out.println("Reading the file");". The exception is propagated to the method that calls readFile. Program execution doesn't resume until a catch-block somewhere in the call stack catches the exception. All methods in the call stack between the method throwing the exception and the method catching it have their execution stopped at the point in the code where the exception is thrown or propagated.

Additional to these exception handling Java also provide a way of closing the resources that we use and ensures there are no leaks. To handle the closing of resources effectively Java provides try-catch with resources, which is useful in closing the resources.


try-catch with resources:


The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.

The following example reads the first line from a file. It uses an instance of BufferedReader to read data from the file. BufferedReader is a resource that must be closed after the program is finished with it:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class StreamsDemo {

  public static void main(final String args[]) throws IOException {

    try (BufferedReader reader = new BufferedReader(new FileReader("C:\\temp\\input-file.txt"));
        BufferedWriter writer = new BufferedWriter(new FileWriter("C:\\temp\\output-file.txt"))) {
      String line;
      while ((line = reader.readLine()) != null) {
        writer.write(line);
      }
    }
  }
}




In this example, the resource declared in the try-with-resources statement is a BufferedReader. The declaration statement appears within parentheses immediately after the try keyword. The class BufferedReader, in Java SE 7 and later, implements the interface java.lang.AutoCloseable. Because the BufferedReader instance is declared in a try-with-resource statement, it will be closed regardless of whether the try statement completes normally or abruptly (as a result of the method BufferedReader.readLine throwing an IOException).


try-catch-finally:

You can attach a finally-clause to a try-catch block. The code inside the finally clause will always be executed, even if an exception is thrown from within the try or catch block. If your code has a return statement inside the try or catch block, the code inside the finally-block will get executed before returning from the method. Here is how a finally clause looks:


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class StreamsDemo {

  public static void main(final String args[]) throws IOException {
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(new FileReader("C:\\temp\\input-file.txt"));
      String line;
      while ((line = reader.readLine()) != null) {
        System.out.println(line);
      }
    } catch (final IOException e) {
      // do something clever with the exception
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (final IOException e) {
          // do something clever with the exception
        }
      }
      System.out.println("--- File End ---");
    }
  }

}

No matter whether an exception is thrown or not inside the try or catch block the code inside the finally-block is executed. The example above shows how the file reader is always closed, regardless of the program flow inside the try or catch block.

Note: If an exception is thrown inside a finally block, and it is not caught, then that finally block is interrupted just like the try-block and catch-block is. That is why the previous example had the reader.close() method call in the finally block wrapped in a try-catch block.

1 comment:

  1. thanks... I came to know new point "try-catch with resources:"

    ReplyDelete