What is Exception Handling in Java?
Exception handling in Java is a mechanism that allows developers to manage runtime errors in a structured way. It involves using specific language constructs to catch exceptions, handle them, and ensure that the program can recover or exit gracefully. The primary constructs used in exception handling are try, catch, finally, and throw. By enclosing code that might generate exceptions in a try block and providing catch blocks to handle those exceptions, developers can prevent errors from causing program crashes and implement appropriate recovery strategies.
Hierarchy of Java Exception Classes
Java's exception handling framework is built around a class hierarchy that starts with the Throwable class. The hierarchy is structured as follows:
- Throwable: The root class for all exceptions and errors.
- Exception: Represents exceptions that a program might want to catch. It includes:
- RuntimeException: Represents exceptions that occur during the program’s execution, which are unchecked and do not require explicit handling.
- Checked Exceptions: Subclasses of Exception that are not subclasses of RuntimeException. They must be either caught or declared in the method signature using throws.
- Error: Represents serious problems that a program typically should not try to handle, such as OutOfMemoryError and StackOverflowError.
Types of Java Exceptions
Java exceptions are categorized into several types:
- Checked Exceptions: These exceptions are checked at compile-time. The programmer must handle them using try-catch blocks or declare them using the throws keyword. Examples include IOException and SQLException.
- Unchecked Exceptions: These exceptions are not checked at compile-time and include RuntimeException and its subclasses. They often represent programming errors, such as NullPointerException and ArrayIndexOutOfBoundsException.
- Errors: These are serious issues that are not typically handled by programs. They include VirtualMachineError, OutOfMemoryError, and StackOverflowError. These usually indicate problems that are beyond the control of the program.
Keywords used in Exception Handling in Java
The five main clauses in exception handling are:
- throw – raises an exception
- throws – reports exception
- try – monitors exception
- catch – handles the exception
- finally – finally can be the last block in the method that executes. In both normal and abnormal termination of the program execution.
Exceptions that can be handled using Exception Handling
All exceptions descend from the Throwable parent class. But the hierarchy quickly divides into two branches: Error and Exception.
An essential element of Exception handling in Java is the Exception hierarchy. The Exception hierarchy is further divided into two branches:
- Exceptions that are derived from RuntimeException
- Exceptions that are not derived from RuntimeException
The general rule is: A RuntimeException happens because the programmer made a programming error. Any other exception occurs because some other thing, such as an I/O error, happened. The compiler checks for exceptional handlers for all the checked or compile-time exceptions.
Inside the Java run-time system, the Error hierarchy defines internal errors and resource exhaust situations. A program should never throw this type of object. If an internal error occurs, a programmer has no choice but to warn the user and manually exit the program. These are highly uncommon circumstances.
Thus Exceptions are recoverable and can be handled by exception handling techniques, whereas Errors are irrecoverable and lead to abnormal termination of the program.
Also see, Swap Function in Java
Exception handling in Java involves three operations:
1. Declaring Checked Exceptions
A Java method must declare the types of checked exceptions it may throw, using the keyword “throws” in its signature.
For example, consider the declaration of the below-given method. After the throws keyword, the name of the potential exceptions is mentioned that the program may encounter during execution.
public void TestThrows() throws Exception1, Exception2 {...}
2. Throwing an exception
A program can throw an exception if it encounters a situation it cannot handle using the keyword “throw”. In other words, When a Java program encounters an abnormal situation, the method having the incorrect code should create an appropriate exception object and throw it to the JVM using the below statement.
public void TestThrow() throws Exception1, Exception2
{
// Exception1 occurs
if ( ... ) throw new Exception1(...);
// construct an Exception1 object and throw to JVM
// Exception2 occurs
if ( ... ) throw new Exception2(...);
// construct an Exception2 object and throw to JVM
}
Note: The keyword to declare the exception in the method’s signature is “throws”. And the keyword to throw an exception object within the method’s body is “throw”.
3. Catching an exception
When a method throws an exception, the JVM looks for a matching exception handler in the call stack. Each exception handler is limited to one type of exception. An exception handler that can handle a given class can also handle its subclasses. The program ends if no exception handler is found in the call stack.
For example, suppose a method method1() declares that it may throw Exception1 and Exception2 in its signature, as follows:
public void method1() throws Exception1, Exception2 { ...... }
There are two ways in which we can use method1 in our program.
1. Via a call to method1() inside a try-catch or try-catch-finally as given below.
public void method2()
{ // no exception declared
try
{
// uses method1() which declares Exception1 & Exception2
method1();
}
catch (Exception1 ex) {
// Exception handler for Exception1
}
catch (Exception2 ex} {
// Exception handler for Exception2
}
}
2. If method2(), which calls method1(), does not want to handle exceptions with a try-catch, it can specify these exceptions to be thrown up the call stack as follows.
public void method2() throws Exception1, Exception2
{
// for the higher-level method to handle
// uses method1() which declares "throws Exception1, Exception2"
method1(); // no need for try-catch
}
Using try-catch
The first step in creating an exception handler is to use a try block to enclose any code that might throw an exception.
A try block looks something like this in general:
try {
code
}
catch and finally blocks
Multiple catch clauses
Exception handlers can be associated by placing one or more catch blocks after the try block. The code inside the catch block is executed when the exception handler is invoked.
try {
} catch (ExceptionType name) {
} catch (ExceptionType name) {
}
- Each catch block is an exception handler that handles the type of exception indicated by its argument.
- The parameter must be the name of a class that inherits from the Throwable class and indicates the type of exception that the handler can handle.
- The exception can be referred to by name in the handler.
- When the exception handler is the first in the call stack with an ExceptionType that matches the type of the exception raised, the runtime system calls it.
Example:
try {
} catch (IndexOutOfBoundsException e)
{
System.err.println("IndexOutOfBoundsException: " + e.getMessage());
}
catch (IOException e)
{
System.err.println("Caught IOException: " + e.getMessage());
}
Displaying a Description of an Exception
To display the description of an exception, simply pass the exception as an argument to the print method.
The below-given program is an implementation of the above problem:
Java
import java.io.*;
public class TestClass {
public static void main(String args[])
{
try {
String a = "Coding Ninjas"; // length is 13
char c = a.charAt(14); // accessing 14th element
System.out.println(c);
}
catch (StringIndexOutOfBoundsException e) {
System.out.println("Displaying the description of Exception:"+e);
}
System.out.println("Execution Completed!!");
}
}
You can also try this code with Online Java Compiler
Run Code
Output
Displaying the description of Exception: java.lang.StringIndexOutOfBoundsException: String index out of range: 14
Execution Completed!!
You can also try this code with Online Java Compiler
Run Code
Note: Exception handlers are capable of much more than simply printing error messages or terminating the program. They can utilise chained exceptions to accomplish error recovery. They can prompt the user to decide or propagate the error up to a higher-level handler.
Nested try statements
A situation may occur in which a part of a block causes one error, and the complete block causes another error. Exception handlers must be nested in such cases.
In the same manner, we can employ a try block within a try block in Java. The context of an exception is pushed into a stack each time a try statement is entered.
An example of nested try blocks is shown below.
Example1: To handle an ArithmeticException, an inner try block is used in this example. The outer try block then handles the ArrayIndexOutOfBoundsException.
Java
import java.io.*;
class TestClass {
public static void main(String args[])
{
// Outer try block
try {
int a[] = { 1, 2, 3, 4, 5, 6, 7 };
// printing element at index 7 i.e out
System.out.println(a[7]);
// inner try block
try {
// division by zero
int x = a[2] / 0;
}
catch (ArithmeticException e2)
{
System.out.println("Arithmetic Exception encountered!!");
}
}
catch (ArrayIndexOutOfBoundsException e1)
{
System.out.println("ArrayIndexOutOfBounds Exception encountered!!");
System.out.println("Catch method of outer try block implemented!!");
}
}
}
You can also try this code with Online Java Compiler
Run Code
Output
ArrayIndexOutOfBounds Exception encountered!!
Catch method of outer try block implemented!!
- If a try block does not have a catch block for a specific exception, the catch block of the parent block is searched for that exception, and if a match is found, the catch block of the parent is executed.
- If none of the catch blocks catches the exception, the Java run-time system will handle it and display a system-generated message.
Example2: Another example of how the nested try block works can be seen here. Inside the body of the parent try block, you can see two try-catch blocks.
Java
import java.io.*;
public class TestClass {
public static void main(String args[]){
//Parent try block
try{
//Child try block1
try{
System.out.println("Inside block1");
//Divide by zero exception........
int b =45/0;
}
catch(ArithmeticException e1){
System.out.println("Exception: e1");
}
//Child try block2
try{
System.out.println("Inside block2");
//Divide by zero exception again........
int b =45/0;
}
catch(ArrayIndexOutOfBoundsException e2){
System.out.println("Exception: e2");
}
}
catch(ArithmeticException e3){
System.out.println("Arithmetic Exception");
System.out.println("Inside parent's catch-1 block");
}
catch(ArrayIndexOutOfBoundsException e4){
System.out.println("ArrayIndexOutOfBoundsException");
System.out.println("Inside parent's catch-2 block");
}
catch(Exception e5){
System.out.println("Exception");
System.out.println("Inside parent's catch-3 block");
}
System.out.println("Ending the parent try-catch block.......");
}
}
You can also try this code with Online Java Compiler
Run Code
Output
Inside block1
Exception: e1
Inside block2
Arithmetic Exception
Inside parent's catch-1 block
Ending the parent try-catch block.......
- Child try-catch block1: Integer divide by zero caused an ArithmeticException since the catch of block1 is handling ArithmeticException “Exception: e1” displayed.
- Child try-catch block2: ArithmeticException occurred again, but block 2’s catch only handles ArrayIndexOutOfBoundsException, so control jumps to the parent try-catch body and looks for the ArithmeticException catch handler in parent’s catch block.
- The message “Inside parent try block” appears because the catch of the parent’s try block handles this exception with a generic Exception handler that handles all exceptions.
- Parent try Catch block: In this case, there was no exception. Hence the message “Ending the parent try-catch block…….” appeared.
Need more insights about the try Block, you can refer to the official java documentation here.
Control flow in try-catch or try-catch-finally
The flow control in all the various combinations of try, catch, and finally, blocks are explained below:
1. Exception occurs in the try block and handled in the catch block
- If a statement in the try block throws an exception, the rest of the try block is skipped, and control is passed to the catch block.
- When the catch block is completed, the control will be transferred to the finally block if it is present in the code, and then the rest of the program will be executed.
Program:
Java
import java.io.*;
public class TestClass
{
public static void main (String[] args){
int[] arr = new int[7];
try
{
int i = arr[7];
// this statement will not be executed
// as exception is raised by above statement
System.out.println("Inside try block");
}
catch(ArrayIndexOutOfBoundsException ex)
{
System.out.println("Inside catch block!!");
}
finally
{
System.out.println("Inside finally block!!");
}
// rest of the program will be executed
System.out.println("Outside try-catch-finally clause");
}
}
You can also try this code with Online Java Compiler
Run Code
Output
Inside catch block!!
Inside finally block!!
Outside try-catch-finally clause
2. Exception occurred in try-block is not handled in catch block:
In certain circumstances, the default handler is called. If there is a final block, it will be executed first, followed by the default handler.
Program:
Java
import java.io.*;
public class TestClass {
public static void main (String[] args)
{
int[] arr = new int[7];
try
{
int i = arr[7];
// this statement will not execute
// as exception is raised by above statement
System.out.println("Inside try block!!");
}
catch(NullPointerException ex)
{
System.out.println("Inside catch block!!");
}
finally
{
System.out.println("Inside finally block!!");
}
// rest of the program will not execute
System.out.println("Outside try-catch-finally clause");
}
}
You can also try this code with Online Java Compiler
Run Code
Output
Inside finally block!!
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 7 out of bounds for length 7
at TestClass.main(TestClass.java:8)
3. Exception doesn’t occur in try-block:
In this situation, the catch block is never executed because it is only supposed to be executed when an exception occurs. If a final block exists, it will be executed before the rest of the program.
Program:
Java
import java.io.*;
public class TestClass {
public static void main (String[] args)
{
try
{
String str = "123";
int num = Integer.parseInt(str);
// this statement will execute
// as no any exception is raised by above statement
System.out.println("End of the try block!!");
}catch(NumberFormatException ex)
{
System.out.println("Inside catch block");
}
finally
{
System.out.println("Inside finally block!!");
}
System.out.println("Outside try-catch-finally clause");
}
}
You can also try this code with Online Java Compiler
Run Code
Output
End of the try block!!
Inside finally block!!
Outside try-catch-finally clause
Using finally
When the try block exits, the finally block is always executed. Even if an unexpected exception occurs, the finally block is executed.
Important points regarding the finally block are given below:
- The finally block is a crucial technique for reducing resource leaks.
- While closing a file or recovering resources, we must place the code in a finally block to ensure the resource is always recovered.
- In these cases, consider utilizing the try-with-resources statement, which automatically releases system resources when they are no longer required.
Refer to this code snippet from java documentation explaining the above utility:
static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
In this example, a finally block has been used to ensure that a resource is closed, regardless of whether the try statement executes normally or is terminated abruptly.
Must Read Static Blocks In Java and Hashcode Method in Java
Frequently Asked Questions
What are the five keywords used in java exception handling?
Java exception handling uses five keywords, try, catch, throw, throws, and finally.
How are the exceptions handled in Java? Specify one method.
The most basic method of handling exceptions is try-catch. Put the code in the try block, and any Java exceptions the code throws will be caught by one or more catch blocks followed by the try block.
Which keyword is used to throw an exception?
The throws keyword is used to specify which exceptions a method can throw, whereas the throw keyword is used to throw an exception explicitly within a method or block of code.
Can we throw an exception manually?
Using the throw keyword, we can explicitly throw a user-defined or predefined exception. To explicitly throw an exception, we must first create the class and then use the throw keyword to throw its object.
Can we catch and throw the same exception in a program?
We can do things like this in the catch block and then rethrow the exception. As a result, a higher level is notified that a system exception has occurred.
Conclusion
This article is designed so that it is helpful for both beginners and those preparing for placements and other tests.
As an initiative towards “Knowledge for all”, Coding Ninjas has brought a few free courses. The free courses cover an essential level of programming so that each student or IT enthusiast is at least familiar with the basic programming concepts.
Happy Learning!