Java exception handling

Exceptions (or exceptional events) are problems that arise during the execution of a program. When an exception occurs, the normal flow of the program is interrupted and the program/application terminates abnormally, which is very user-unfriendly. Therefore, handle these exceptions reasonably.

Exceptions can occur for many different reasons, the following are some of the situations in which exceptions can occur.

  • User entered invalid data.
  • Could not find a file to open.
  • The network connection was lost during the communication, or the JVM ran out of memory.

Some exceptions are caused by user error, and some exceptions are caused by programmer error, or by some kind of physical resource.

Based on there are three types of exceptions, you need to understand them to understand how exception handling works in Java.

  • Checked Exceptions
  • Unchecked Exceptions
  • Errors

 

  • Checked Exceptions − Checked exceptions are exceptions that are checked (notified) by the compiler at compile time, these exceptions are also known as compile time exceptions. These exceptions cannot simply be ignored, programmers should write code to handle them.
    For example, if you use FileReader class in your program to read data from a file, if the file specified in its constructor doesn't exist, then a FileNotFoundException occurs, and the compiler prompts the programmer to handle the exception.

 

Sample code -

import java.io.File;
import java.io.FileReader;

public class FilenotFoundDemo {

   public static void main(String args[]) {        
      File file = new File("D://file.txt");
      FileReader fr = new FileReader(file); 
   }
}

If the above program is compiled, the following exception occurs.

C:\>javac FilenotFoundDemo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
                      ^
1 error
 

Note - Since the FileReaderclass read() and close() method throw IOException, you can see that the compiler notices that both exceptions are required to be handled IOExceptionas along with FileNotFoundException

 

  • Unchecked Exceptions − Unchecked exceptions are exceptions that occur at execution time. These are also called runtime exceptions. These include programming errors, such as logic errors or improper use of APIs, runtime exceptions ignored by compile time.
    For example, if you declare an array of size 5 in your program, but you try to call the 6th element of the array then an ArrayIndexOutOfBoundsExceptionexception occurs.

    public class UncheckedDemo {
    
     public static void main(String args[]) {
        int num[] = {1, 2, 3, 4};
        System.out.println(num[5]);
     }
    }
    
    

    If the above program is compiled and executed, the following exception occurs.

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
      at Exceptions.UncheckedDemo.main(UncheckedDemo.java:8)
    
  • Error - This is not strictly an exception, it is a problem beyond the control of the user or programmer. Errors are usually ignored in code because rarely anything is done about them. For example, if a stack overflow occurs, there will be an error. They are also ignored at compile time.

 

1. Exception Hierarchy

All exception classes are subtypes of java.lang.Exception class. The Exception class is a subclass of a Throwable class. In addition to the Exception class, there is another subclass named Error, which is derived from the Throwable class.

Errors are exceptional conditions that occur in case of critical failures, and Java programs do not handle these conditions.

Example: JVM is out of memory. Normally, programs cannot recover from errors.

The Exception class has two main subclasses: IOException class and RuntimeException Class

Java Exception Hierarchy

 

Following is a list of the most common checked and unchecked Java built-in exception classes .

 

2. Exception methods

Following is the list of  methods available in the Throwable class.

Numbering method abnormal
1 public String getMessage() Returns a detailed message about the exception that occurred Throwable, initialized in the constructor.
2 public Throwable getCause() Returns the reason for the exception represented by the Throwable object.
3 public String toString() Returns the class name connected with the getMessage() result.
4 public void printStackTrace() Prints the result of toString() along with the stack trace to System.err, the error output stream
5 public StackTraceElement [] getStackTrace() Returns an array containing each element on the stack trace. The element at index 0represents the top of the call stack, while the last element in the array represents the method at the bottom of the call stack.
6 public Throwable fillInStackTrace() Populates this Throwable object's stack trace with the current stack trace, adding any previous information from the stack trace.

 

3. Catch exceptions

Exceptions can be caught using a combination of the try and catch keywords in a method. try/catch Blocks are placed around code that may generate exceptions. Code within a try/catch block is referred to as protected code, and the syntax for using try/catch looks like the following

grammar

try {
   // Protected code
} catch (ExceptionName e1) {
   // Catch block
}

Put exception-prone code in try blocks. When an exception occurs, the exception is catch handled by the block associated with it. Each try block should be immediately followed by a catch block or blocks finally.

catch statement involves declaring the type of exception that is attempted to catch. If an exception occurs in the protected code, the try following catch block (or blocks) are checked. If the type of exception that occurred is listed in the catch block, the exception is passed to the catch block just like a parameter is passed to a method parameter.

example

The following is 2an array declared with elements, then attempting to access the element of the array throws an exception 3.

// ExcepTest.java
import java.io.*;

public class ExcepTest {

   public static void main(String args[]) {
      try {
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}
 

Execute the above sample code and get the following results:

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block
Shell

4. Multiple try blocks

A try block can be followed by multiple catch blocks, the syntax of multiple catch blocks is as follows −

grammar

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}
 

Three blocks are placed in the catch statement above , but any number of blocks can be obtained in a single attempt. If an exception occurs in the protected code, the exception will be thrown to the first catch If the data type of the exception thrown matches ExceptionType1, it gets caught there. If not, the exception is passed to the second catch statement. This continues until the exception is caught, in which case the current method stops executing and the exception is thrown to the previous method on the call stack.

 

Example

try/catchFollowing is the code snippet showing how to use multiple statements.

try {
   file = new FileInputStream(fileName);
   x = (byte) file.read();
} catch (IOException i) {
   i.printStackTrace();
   return -1;
} catch (FileNotFoundException f) // Not valid! {
   f.printStackTrace();
   return -1;
}
 

Catching Multiple Types of Exceptions
Since Java 7, it is possible to use a single catchblock to handle multiple exceptions, this feature simplifies the code. Below is an application example −

catch (IOException|FileNotFoundException ex) {
   logger.log(ex);
   throw ex;
 

5. throws/throw keyword

If a method does not handle checked exceptions, the method must declare it using throws the keyword. The keyword should be placed at the end of the method signature.

An exception can be thrown using the throw keyword, either a newly instantiated exception or a freshly caught exception.

The difference between the throws and throw keywords is for deferring handling of checked exceptions and throw for calling exceptions explicitly.

The following method declares that it throws RemoteException -

import java.io.*;
public class className {

   public void deposit(double amount) throws RemoteException {
      // Method implementation
      throw new RemoteException();
   }
   // Remainder of class definition
}

A method can be declared to throw multiple exceptions, in which case the exceptions are declared in a comma-separated list. For example, the following method declares that it throws RemoteException and InsufficientFundsExceptionexception −

import java.io.*;
public class className {

   public void withdraw(double amount) throws RemoteException, 
      InsufficientFundsException {
      // Method implementation
   }
   // Remainder of class definition
}

6. finally block

finally block after try block or catch blocks. Regardless of whether an exception occurs in the protected code block, the code in the block will eventually be executed finally.

Use a finally block to run any sanitization-type statements to be executed regardless of what is happening in the protected code.

finallyBlocks are placed at catchthe end of the block and its syntax syntax is as follows −

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}finally {
   // The finally block always executes.
}

Example

public class ExcepTest {

   public static void main(String args[]) {
      int a[] = new int[2];
      try {
         System.out.println("Access element three :" + a[3]);
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println("Exception thrown  :" + e);
      }finally {
         a[0] = 6;
         System.out.println("First element value: " + a[0]);
         System.out.println("The finally statement is executed");
      }
   }
}

Execute the above sample code and get the following result −

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed
 

When using finally, you need to pay attention to the following rules -

  • A catch clause cannot exist without a try statement.

  • It is not compulsory to have finally clauses whenever a try/catch block is present.

  • The try block cannot be present without either catch clause or finally clause.

  • Any code cannot be present in between the try, catch, finally blocks.

 

7. try-with-resources

In general, when using any resources like streams, connections, etc., you want to close them explicitly using finally blocks. In the following program, we are reading data from a file using FileReader and we are closing it using finally block

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class ReadData_Demo {

   public static void main(String args[]) {
      FileReader fr = null;        
      try {
         File file = new File("file.txt");
         fr = new FileReader(file); char [] a = new char[50];
         fr.read(a);   // reads the content to the array
         for(char c : a)
         System.out.print(c);   // prints the characters one by one
      } catch (IOException e) {
         e.printStackTrace();
      }finally {
         try {
            fr.close();
         } catch (IOException ex) {        
            ex.printStackTrace();
         }
      }
   }
}
Java

try-with-resources, also known as automatic resource management, is a new exception handling mechanism introduced in Java 7 that automatically closes resources used in try/catch blocks.

To use this statement, simply declare the desired resource within parentheses, and the created resource will be automatically closed at the end of the block. Following is the syntax of the try-with-resources statement.

grammar

try(FileReader fr = new FileReader("file path")) {
   // use the resource
   } catch () {
      // body of catch 
   }
}

Following is the program to read data from a file using try-with-resources statement.

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

public class Try_withDemo {

   public static void main(String args[]) {
      try(FileReader fr = new FileReader("E://file.txt")) {
         char [] a = new char[50];
         fr.read(a);   // reads the contentto the array
         for(char c : a)
         System.out.print(c);   // prints the characters one by one
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}
 

When using try-with-resources statements, keep the following points in mind.

  • To use a class with try-with-resources statement it should implement AutoCloseable interface and the close() method of it gets invoked automatically at runtime.

  • You can declare more than one class in try-with-resources statement.

  • While you declare multiple classes in the try block of try-with-resources statement these classes are closed in reverse order.

  • Except the declaration of resources within the parenthesis everything is the same as normal try/catch block of a try block.

  • The resource declared in try gets instantiated just before the start of the try-block.

  • The resource declared at the try block is implicitly declared as final

 

8. User-defined exceptions

You can create your own exceptions in Java. While writing your own exception classes, please note the following points −

  • All exceptions must be subclasses of Throwable .
  • If you want to write checked exceptions that are automatically enforced by handling or declaration rules, you need to extend the Exception class.
  • If you want to write runtime exceptions, you need to extend the RuntimeException class.

You can define your own Exception class as follows −

class MyException extends Exception {
}

You just need to extend the predefined Exception classes to create your own Exception. These are checked exceptions. The following InsufficientFundsException class is a user-defined exception that extends the Exception class to make it a checked exception. Exception classes are like any other class, containing useful fields and methods.

example

//InsufficientFundsException.java
import java.io.*;

public class InsufficientFundsException extends Exception {
   private double amount;

   public InsufficientFundsException(double amount) {
      this.amount = amount;
   }

   public double getAmount() {
      return amount;
   }
}

To demonstrate how to use user-defined exceptions, the following CheckingAccount class contains a withdraw() method that throws an InsufficientFundsException

// CheckingAccount.java
import java.io.*;

public class CheckingAccount {
   private double balance;
   private int number;

   public CheckingAccount(int number) {
      this.number = number;
   }

   public void deposit(double amount) {
      balance += amount;
   }

   public void withdraw(double amount) throws InsufficientFundsException {
      if(amount <= balance) {
         balance -= amount;
      }else {
         double needs = amount - balance;
         throw new InsufficientFundsException(needs);
      }
   }

   public double getBalance() {
      return balance;
   }

   public int getNumber() {
      return number;
   }
}
 

The following BankDemo program demonstrates how to call the deposit() and withdraw() methods of CheckingAccount.

// BankDemo.java
public class BankDemo {

   public static void main(String [] args) {
      CheckingAccount c = new CheckingAccount(101);
      System.out.println("Depositing $500...");
      c.deposit(500.00);

      try {
         System.out.println("\nWithdrawing $100...");
         c.withdraw(100.00);
         System.out.println("\nWithdrawing $600...");
         c.withdraw(600.00);
      } catch (InsufficientFundsException e) {
         System.out.println("Sorry, but you are short $" + e.getAmount());
         e.printStackTrace();
      }
   }
}

Execute the above sample code and get the following result −

Depositing $500...

Withdrawing $100...

Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsException
         at CheckingAccount.withdraw(CheckingAccount.java:25)
         at BankDemo.main(BankDemo.java:13)
 

Common exception

In Java, two categories can be defined: exceptions and errors.

  • JVM Exceptions − These are exceptions/errors thrown exclusively or logically by the JVM. Examples: NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException.
  • Programmatic Exceptions − These exceptions are explicitly thrown by the application or API programmer. Examples: IllegalArgumentException, IllegalStateException