Exception Handling in Java Programming

What is an Exception in Java?

An exception is an event that occurs during the execution of a program and disrupts the normal (expected) flow of the program. In programming, the word “exception” refers to an “exceptional event.”

Related Terminologies

  • Exception object: As soon as an exception occurs within a method, the method returns an object to the runtime system. This object is called an exception object which contains data regarding the exception.
  • Throwing an exception: The creation of an exception object and giving its control to the runtime system is called throwing an exception.
  • Exception handler: The block of code designed to handle an exception(s) is called an exception handler.

What happens when an exception occurs?

Suppose we’ve written a method that throws an exception on executing. As soon as the exception is thrown, the runtime system attempts to find an exception handler. The system searched those methods that had been called to get to the method with the exception. This list of methods is often termed a call stack.

The search proceeds in top-down order in the call stack to find the suitable exception handler. That is, first the method with the exception is searched, then the method which called this method, and so on….

Top-down search in the call stack to find the suitable exception handler

Search is done from top to bottom

Note: An exception handler is considered suitable if the thrown exception’s type matches the type that the handler can handle. In case the system doesn’t find a suitable handler, the program terminates. 

The Catch or Specify requirement

A good java method must ensure at least one of the following:

  • It should be able to catch and handle the exception (using try and catch).
  • It should specify the possible exceptions it can throw(using throws).

Types of Exceptions in Java

Exceptions are depicted by certain classes in Java. The java.lang.Throwable is the root class in Java Exceptions, which has two children Exception and Error.

Checked Exceptions: These are the most anticipated exceptions and are recoverable also. All classes except RuntimeException and Error class families have checked exceptions.

A trivial example is regarding File handling. The user gives the name of a file to read, if it exists, then there’s no harm; otherwise, the method will throw java.io.FileNotFoundException.

import java.io.FileReader;
class CheckedException{
     public static void main (String[] args) {
     
     //reading file "name.txt"
     FileReader file= new FileReader("name.txt");
      //The bold part may throw an exception if file does 
      // not exist or for some other I/O reason.
     }
}

Unchecked exceptions: Error and Runtime exception.

  • Error: These are exceptions that are non-anticipable and unrecoverable hence, they are not subject to check or specify requirements. Consider the previous example of file handling, this time the “Exception.txt” is created successfully but we can not operate on it due to some system malfunction, then java.io.IOError will be thrown.
  • Runtime Exception: Just like errors, these are non-anticipable and unrecoverable, generally caused by a logical error or improper use of API or some other bug. A trivial example is the “divide by zero” case, where we divide a number by zero (illogical). In such a case, java.lang.ArithmeticException is thrown.

Types of exception handling in Java

Now let’s first see how to catch and handle (writing exception handler) the exceptions, followed by how to specify the exceptions thrown by a method.

Writing the Exception Handler (try, catch, and finally)

Consider the example of a class named FileHandle:

import java.io.File;    
import java.io.FileWriter;
import java.io.IOException;
public class FileHandle {
    private int divisor;
    private String fileName;
    private File file;
    
    public FileHandle(int divisor, String fileName) {
           this.divisor = divisor;
           this.fileName = fileName;
           file = new File(fileName);
    }
    public void writeFile(String input, int dividend) {
          
            //creation of new file using createNewFile
               file.createNewFile();
           //writing into file
               FileWriter abc = new FileWriter(fileName);
               abc.write(input);
               abc.write(Integer.toString(dividend/divisor));
               abc.close();
    }
    public static void main(String[] args) throws IOException {
        
        //giving a wrong path
        String path = "tmp"+File.separator+"HIJAVA.txt";
        
        FileHandle object = new FileHandle(2,path);
        object.writeFile("123556",2);
    }
}

The FileHandle() constructor takes an integer as a divisor and a string as the path where the file will be created. The writeFile() method takes string and integer as arguments, creates the required file with createNewFile(), and writes in it using FileWriter class. 

The first line in boldface may throw an IOException if the file is not created properly. Similarly, the FileWriter constructor may also throw the same exception. If the file is successfully created, the third line in boldface may throw an Arithematic exception in case the divisor is 0.

Output message with the wrong path:

Exception in thread "main" java.io.IOException: The system cannot find the path specified
 at java.io.WinNTFileSystem.createFileExclusively(Native Method)
 at java.io.File.createNewFile(File.java:1023)
 at FileHandle.writeFile(FileHandle.java:16)
 at FileHandle.main(FileHandle.java:28)

Notice that only the exception thrown by the createNewFile() method is displayed and the arithmetic error is not shown. This is because createNewFile() throws IOException error which is a checked exception, whereas ArithematicException is an unchecked exception.

The try Block

It is the first component of any exception handler. Syntax :

try {
       //code
}
catch and finally blocks...

The code block contains the code that may throw exception(s). We’ll leave catch and finally blocks for later.

To make an exception handler for the writeFile() method, we will enclose the exception-throwing statements in the tryblock. We can either enclose all statements in one block or treat each statement individually. Here’s the code:

FileWriter abc = null;
try{
    file.createNewFile();
   
    //writing into file
    abc = new FileWriter(fileName);
    abc.write(input);
    abc.write(Integer.toString(dividend/divisor));
    abc.close();
}
catch and finally ...

If an exception occurs inside the try block, it is handled by the exception handler that is connected with it. The catch block associated with the try block handles the exception.

The catch Block

The catch block should come directly after the try block. No code can be between the end of the try block and the beginning of the first catch block. There can be more than one catch associated with a single try block.

Syntax:

try {
    //code which may throw exceptions
} catch (ExceptionType varname){
   
    //code to handle exception
} catch (ExceptionType varname){
   
    //code to handle exception
}

Each catch block handles the type of exception indicated by its argument. That is, ExceptionType should be a valid class that inherits the Throwable class. As soon as the code in the try block throws an exception, the runtime system searches for an appropriate catch block compatible with thrown exception (the ExceptionType matches).

For our writeFile() we write the following catch blocks:

try{
    //same as previous
} catch (IOException e) {
    System.err.println(e.getMessage());
} catch (ArithmeticException e) {
    System.err.println(e.getMessage());
}

The finally Block

The finally block is executed after completion of the try-catch block irrespective of the facts whether an exception is thrown or an exception is thrown but not handled or the thrown exception is handled. But, it will not be executed if the JVM exits while executing the try-catch block or if some fatal error occurs and the program is aborted.

  • Each try block can have only one finally block which is preceded by one or more catch blocks.
  • It is a good practice to put the cleanup code in a finally block even when no exceptions are expected.

In our example, we should close the FileWriter and file object.

finally{
        if(file!=null){
            System.out.println("closing file");
        }
        else{
            System.out.println("file not open");
        }
        if(abc!=null){
            System.out.println("closing abc");
        }
        else{
            System.out.println("abc not open");
        }
 }

Now, the writeFile() method will be:

public void writeFile(String input, int dividend){
              
       //creation of new file using createNewFile
       FileWriter abc=null;
       
       try{
            file.createNewFile();
            //writing into file
            abc = new FileWriter(fileName);
            abc.write(input);
            abc.write(Integer.toString(dividend/divisor));
       }catch (IOException e) {
            System.err.println(e.getMessage());
       } catch (ArithmeticException e) {
            System.err.println(e.getMessage());
       }finally{
            if(file!=null){
                  System.out.println("closing file");
            }
            else{
                  System.out.println("file not open");
            }
            if(abc!=null){
                  System.out.println("closing abc");
            }
            else{
                  System.out.println("abc not open");
            }
       }
}

The throws clause

We made an exception handler for writeFile() in the method itself. But we can allow a method further up in the call stack to handle the exception thrown by the writeFile() method. Thus we state that:

If the writeFile() method doesn’t catch the checked exception that can occur within it, then it must specify the exceptions it can throw.

Generally, it is a good practice to specify the exceptions which can be thrown by the method even if we provide a handler in it. This can be done using the keyword throws with the writeFile() method. 

Syntax:

public void writeFile(String input, int dividend) throws ExceptionType1, ExceptionType2... {
          //method body
}

The boldfaced part is called the throws clause of the method. ExceptionType1, ExceptionType2…, and so on are the possible exceptions thrown by the method.

NOTE: Unchecked exceptions are not mandatory in the throws clause.

Thus we can write:

public void writeList(String input, int dividend) throws IOException {
}
or
public void writeList(String input, int dividend) throws IOException, ArithmeticException {
}

Throwing exceptions (throw)

We are able to handle and catch exceptions because they are being thrown by some other part of the program or system. Throwing exceptions can be done manually by the throw statement. It requires a throwable object as an argument. Throwable objects are objects of any subclass of the Throwable class. Syntax:

throw object;
//throw is a keyword

Example:

public void checkDivideByZero(int divisor) {
       if(divisor==0) {
            throw new ArithmeticException("Divide By Zero error.");
       }
}

NOTE: throw and throws are two different keywords and are completely different. The throws clause is used to specify the exceptions that a method may throw. Whereas, the throw statement actually throws the exceptions.

Further ideas

  • There exist a different type of try statement known as the try-with-resources statement. It is a try statement that declares one or more resources. 
  • The exceptions are thrown by the throw statement (not throws). With help of it, we can create our own exception classes.
  • A method can respond to an exception by throwing another exception. This is where chained exceptions come into play.

Enjoy learning, Enjoy oops!

More from EnjoyAlgorithms

Self-paced Courses and Blogs