Exceptions that can be handled using Exception Handling
11.
Exception handling in Java involves three operations:
11.1.
1. Declaring Checked Exceptions
11.2.
2. Throwing an exception
11.3.
3. Catching an exception
11.3.1.
1. Via a call to method1() inside a try-catch or try-catch-finally as given below.
11.3.2.
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.
12.
Using try-catch
13.
Multiple catch clauses
14.
Displaying a Description of an Exception
14.1.
Java
15.
Nested try statements
15.1.
Java
15.2.
Java
16.
Control flow in try-catch or try-catch-finally
16.1.
1. Exception occurs in the try block and handled in the catch block
16.2.
Java
16.3.
2. Exception occurred in try-block is not handled in catch block
16.4.
Java
16.5.
3. Exception doesn’t occur in try-block
16.6.
Java
17.
Using finally
18.
Advantages of Exception Handling in Java
19.
Frequently Asked Questions
19.1.
When to use try-catch?
19.2.
What are the five keywords used in java exception handling?
19.3.
How are the exceptions handled in Java? Specify one method.
19.4.
Which keyword is used to throw an exception?
19.5.
Can we throw an exception manually?
19.6.
Can we catch and throw the same exception in a program?
Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
Exception handling is a critical feature in Java that ensures the robustness and reliability of your applications. It provides a structured approach to managing runtime errors, allowing programs to respond gracefully to unexpected situations without crashing. By using Java's exception handling mechanisms, you can capture and address errors such as invalid input, network failures, and file operations issues, thereby enhancing user experience and maintaining system stability. In this blog, we will delve into the fundamentals of exception handling in Java, exploring key concepts such as try-catch blocks, throwing exceptions, and creating custom exceptions.
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:
Here is a diagram showing the hierarchy of Java Exception classes:
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.
Exceptions in Java
Exceptions are divided into two categories:
1. Checked Exceptions
Checked exceptions are checked at compile-time, meaning the compiler ensures they are handled using try-catch blocks or declared using throws.
Example:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class CheckedExceptionExample {
public static void main(String[] args) {
try {
File file = new File("test.txt");
FileReader fr = new FileReader(file); // May throw IOException
} catch (IOException e) {
System.out.println("File not found: " + e.getMessage());
}
}
}
You can also try this code with Online Java Compiler
Common checked exceptions: IOException, SQLException
2. Unchecked Exceptions
Unchecked exceptions occur at runtime and are usually caused by programming errors. They do not require explicit handling.
Example:
public class UncheckedExceptionExample {
public static void main(String[] args) {
int a = 10, b = 0;
int result = a / b; // Throws ArithmeticException
}
}
You can also try this code with Online Java Compiler
Common unchecked exceptions: NullPointerException, ArithmeticException
Errors in Java
Errors represent critical failures in the JVM or system resources. Unlike exceptions, errors cannot be handled or recovered from using try-catch blocks.
Common Errors in Java
OutOfMemoryError: Occurs when the JVM runs out of memory.
public class StackOverflowExample {
public static void recursiveMethod() {
recursiveMethod(); // Infinite recursion
}
public static void main(String[] args) {
recursiveMethod();
}
}
You can also try this code with Online Java Compiler
StackOverflowError: Happens when a program has excessive recursive calls.
public class MemoryErrorExample {
public static void main(String[] args) {
int[] largeArray = new int[Integer.MAX_VALUE]; // Causes OutOfMemoryError
}
}
You can also try this code with Online Java Compiler
Exceptions are recoverable errors caused by faulty code and should be handled using try-catch.
Errors are serious system issues that cannot be recovered from.
Keywords used in Exception Handling in Java
The five main clauses in exception handling are:
throw – Raises an Exception
The throw keyword in Java is used to explicitly raise (or throw) an exception. It is typically used inside a method when a specific condition is encountered that should not be handled by the method itself. The throw statement is followed by an instance of Throwable (usually an exception object). Example:
if (age < 18) {
throw new IllegalArgumentException("Age must be 18 or above");
}
throws – Reports Exception
The throws keyword is used in a method signature to report one or more exceptions that the method might throw. This informs the caller of the method that it must handle or further declare the exception. It is mainly used with checked exceptions. Example:
public void readFile(String filePath) throws IOException {
FileReader reader = new FileReader(filePath);
}
try – Monitors Exception
The try block is used to wrap code that might throw an exception. It monitors the code and ensures that if an exception occurs, the control is transferred to the appropriate catch block. It is the starting point of exception handling in Java. Example:
try {
int result = 10 / 0;
}
catch – Handles the Exception
The catch block is used to handle the exception that occurs in the try block. Each catch block handles a specific type of exception. Multiple catch blocks can be used to handle different exception types separately. Example:
try {
int[] arr = new int[5];
arr[10] = 50;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Array index is out of bounds!");
}
finally – Executes After Try/Catch
The finally block contains code that is guaranteed to execute after the try and catch blocks, regardless of whether an exception was thrown or not. It is commonly used for resource cleanup, such as closing files or releasing database connections. Example:
try {
FileInputStream fis = new FileInputStream("data.txt");
} catch (FileNotFoundException e) {
System.out.println("File not found.");
} finally {
System.out.println("Closing the file.");
}
Difference Between Exception and Error in Java
In Java, Exceptions and Errors are two types of Throwable objects that handle abnormal situations during program execution. Exceptions represent conditions a program can handle and recover from, while Errors indicate serious issues beyond a program’s control. Understanding their differences helps developers write robust and error-free applications by implementing proper exception handling mechanisms.
Comparison Table: Exception vs. Error
Aspect
Exception
Error
Definition
An unexpected event that occurs during program execution and can be handled.
A serious system-level issue that a program cannot recover from.
Cause
Caused by faulty logic, incorrect input, or external issues.
Caused by system failures, hardware malfunctions, or resource limitations.
Examples
NullPointerException, IOException
OutOfMemoryError, StackOverflowError
Exceptions that can be handled using Exception Handling
All exceptions descend from the Throwableparent 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.
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.
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.
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
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
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
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
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
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
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
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
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
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
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
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
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.
Exception handling in Java is a crucial mechanism that ensures smooth program execution by managing runtime errors. It prevents abrupt program termination and provides a structured way to handle unexpected issues. Java uses try, catch, finally, and throw to detect, handle, and recover from exceptions, making code more robust and maintainable. Proper exception handling improves program stability, debugging, and error management.
Provision to Complete Program Execution
Exception handling allows the program to continue running even if an error occurs. Without exception handling, an unhandled exception would cause an abrupt program termination. By using try-catch blocks, developers can catch the exception and take corrective actions, ensuring the program runs smoothly without unexpected crashes. This feature is especially useful in applications that require continuous execution, such as banking systems or online transactions.
Easy Identification of Program Code and Error-Handling Code
Exception handling separates normal code from error-handling logic, improving readability and maintainability. Instead of mixing error-checking conditions throughout the program, Java allows developers to handle exceptions separately using catch blocks. This makes the main program logic cleaner and more understandable while keeping error-handling mechanisms centralized and efficient.
Propagation of Errors
Java allows exceptions to be propagated up the call stack using the throws keyword. This means that if a method does not handle an exception, it can pass it to the caller method, which can then handle it at a higher level. This approach is beneficial for large applications where errors need to be handled centrally instead of at every method level, simplifying debugging and maintenance.
Meaningful Error Reporting
Java exceptions provide detailed error messages and stack traces that help developers quickly identify and resolve issues. The getMessage() and printStackTrace() methods in Java’s Exception class provide insights into where and why the error occurred. This structured error reporting helps in debugging by pinpointing the exact source of the problem, making troubleshooting more efficient.
Identifying Error Types
Exception handling helps differentiate between checked and unchecked exceptions, enabling developers to implement appropriate handling mechanisms. Checked exceptions must be handled explicitly using try-catch or throws, ensuring potential errors are addressed. Unchecked exceptions, such as NullPointerException or ArithmeticException, are runtime errors that can be avoided with proper validation and coding practices. Understanding these distinctions helps write more reliable and error-free programs.
Frequently Asked Questions
When to use try-catch?
Use try-catch when you expect code might throw exceptions and want to handle them gracefully without crashing the program.
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
In this article, we learned Java Exception Handling, an essential mechanism for handling runtime errors and ensuring program stability. We discussed key concepts such as try-catch blocks, finally, throw, and throws, along with checked and unchecked exceptions. Proper exception handling improves code robustness and maintainability, making Java applications more reliable. Understanding these concepts allows developers to write efficient and error-free programs.