Exception handling in Java is one of the important feature that allows us to handle the runtime errors caused by exceptions so that the regular flow of the application can be maintained. In this tutorial, we will learn about exceptions, types of exceptions, exception classes and how to handle exceptions in java program.
What is an Exception
Exception is an unwanted or unexpected event, which occurs during the execution of a program. When an Exception occurs the normal flow of the program is disrupted and the program terminates abnormally, which is not recommended, therefore, these exceptions needs to be handled.
By handling the exceptions we can provide a failure handling mechanism for the issue rather than a system generated error message and abrupt termination of program.
Exceptions can be caught and handled by the java program. When an exception occurs, it creates an exception object. It contains information about the exception, like name and description of the exception, the state of the program when the exception occurred and stack trace.
There can be many reasons that can cause a java program to throw exception such as:
- Network connection problem.
- Invalid user input.
- Trying to open a non-existing file.
- Arithmetic exception like division by zero.
- Hardware issues like not enough memory.
Difference between Exception and Error
Errors indicate that something severe enough has gone wrong, the application should crash rather than try to handle the error. Errors represent irrecoverable conditions such as Java virtual machine (JVM) running out of memory, memory leaks, infinite recursion, etc. Errors are usually beyond the control of the programmer.
Exceptions are events that occurs in the code like NullPointerException, ArithmeticException, IllegalArgumentException etc. Exception indicates conditions that a reasonable application might try to catch. A programmer can handle such conditions and take necessary corrective actions.
Java Exception Hierarchy
All exception are subclasses of class Throwable, which is the base class of the class hierarchy. Other than the exception class there is another subclass called Error which is derived from the Throwable class. Here is a diagram of the exception hierarchy in Java.
Types of Exceptions
Checked exceptions and Unchecked exceptions are the two types of exceptions in Java.
Checked exceptions
All exceptions other than Runtime Exceptions are known as Checked exceptions. It is also known as IOException. They are checked by the compiler at the compile-time and the programmer is prompted to handle these exceptions. If these exceptions are not handled/declared in the program, you will get compilation error.
Some examples of checked exceptions are:
- ClassNotFoundException : The specified class cannot be found in the classpath.
- FileNotFoundException : Trying to access a file which don't exist.
Unchecked Exceptions
Runtime Exceptions are also known as Unchecked Exceptions. A runtime exception happens due to a programming error. These exceptions are not checked at compile-time, it’s the responsibility of the programmer to handle these exceptions to avoid abrupt exit.
Some examples of unchecked exceptions are:
- ArithmeticException : Dividing by 0
- IllegalArgumentException : Method has been passed an illegal argument.
- NullPointerException: A variable is accessed which is not pointing to any object and refers to null.
- ArrayIndexOutOfBoundsException : Out of bounds array access.
Compiler will never force you to catch such exception. These exceptions are caused by programmers fault. For example, ArrayIndexOutOfBoundsException occurs when we access an array with an invalid index. This means that the index is either less than zero or greater than or equal to the size of the array.
Catching Exceptions using try-catch block
The try-catch block is used to handle exceptions in Java. We place the code that might generate an exception inside the try block. Every try block is followed by a catch block. Code within a try block is referred to as protected code. Here's the syntax of try-catch block:
try { // Protected code } catch (ExceptionClass e) { // Catch block }
A catch statement involves declaring the type of exception you are trying to catch. When an exception occurs in the protected code, the catch block(s) that follows the try block is checked. If the type of exception that occurred matches with the type of exception defined in that catch block, the exception is passed to the catch block and statements inside the catch block is executed.
If none of the statements in the try block generates any exception, the catch block is ignored.
Java Program for try-catch block
public class TryCatchBlock { public static void main(String[] args) { // Array of size 10 int[] intArray = new int[10]; try { // Code to generate Array Index Out Of // Bounds Exception. int num = intArray[100]; } catch (ArrayIndexOutOfBoundsException e) { System.out.println(e.toString()); } System.out.println("After try-catch block"); } }Output
java.lang.ArrayIndexOutOfBoundsException: 100 After try-catch block
In above program, we declared and array called "intArray" of size 10. The code inside try block tries to access the 100th element of the array which generates an ArrayIndexOutOfBoundsException exception because array index is more than the size of array.
Java finally block
The finally block follows a try-catch block. The finally block always gets executed no matter whether there is an exception or not. The finally block is optional and there can be only one finally block for each try block. A finally block allows us to run any cleanup type statements that you want to execute, irrespective of what happens in the protected code. Here's the syntax of finally block:
try { // Protected code } catch (ExceptionClass e) { // Catch block }finally { // Finally block always executes }
If an exception occurs, the finally block gets executed after the try-catch block. Otherwise, it is executed after the try block.
Java Program for try-catch block
public class TryCatchFinallyBlock { public static void main(String[] args) { // Array of size 10 int[] intArray = new int[10]; try { // Code to generate Array Index Out Of // Bounds Exception. int num = intArray[100]; } catch (ArrayIndexOutOfBoundsException e) { System.out.println(e.toString()); } finally { System.out.println("Inside finally block"); } System.out.println("After try-catch block"); } }Output
java.lang.ArrayIndexOutOfBoundsException: 100 Inside finally block After try-catch block
In the above example, the code inside try block tries to access the 100th element of the array which generates an ArrayIndexOutOfBoundsException exception. The exception is caught by the catch block and then the finally block gets executed.
- A catch block can only exist with a try block.
- We can have multiple catch blocks for different exceptions with a try block.
- A finally block always gets executed no matter whether there is an exception or not.
- It is not compulsory to have finally block with every a try-catch block.
- Every try block is followed by either a catch block or finally block.
Java throw keyword
The Java throw keyword is used to throw an exception explicitly. We specify the exception object which is to be thrown. When we throw an exception, the flow of the program moves from the try block to the catch block. We can throw either checked or unchecked exceptions in Java by throw keyword.
public class JavaThrowKeyword { public static void generateException() { // throw an exception throw new NullPointerException("Null pointer exception"); } public static void main(String[] args) { generateException(); } }Output
Exception in thread "main" java.lang.NullPointerException: Null pointer exception at com.tcc.java.tutorial.JavaThrowKeyword.generateException(JavaThrowKeyword.java:4) at com.tcc.java.tutorial.JavaThrowKeyword.main(JavaThrowKeyword.java:8)
In the above program, we are explicitly throwing NullPointerException using the throw keyword inside generateException method.
Java throws keyword
Java throws keyword is used in the method signature to declare an exception which might be thrown by the method. If a method does not handle exceptions, the type of exceptions that may occur within it must be specified in the throws clause.
public class JavaThrowsKeyword { public static void generateException() throws ArrayIndexOutOfBoundsException { // throw an exception throw new ArrayIndexOutOfBoundsException( "Throwing Exception"); } public static void main(String[] args) { try { generateException(); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(e.toString()); } } }Output
java.lang.ArrayIndexOutOfBoundsException: Throwing Exception
In the above program, The generateException() method specifies that an ArrayIndexOutOfBoundsException can be thrown. The main() method calls this method and handles the ArrayIndexOutOfBoundsException exception if it is thrown using a try-catch block.
Conclusion
Exception handling is an integral part of writing robust and reliable Java applications. By understanding the exception hierarchy, using try-catch blocks effectively, and following best practices, developers can create code that gracefully handles errors and unexpected situations. Whether you are working on a small project or a large-scale enterprise application, mastering exception handling is essential for delivering high-quality software that meets user expectations.