Exception Handling in Java
The Exception Handling in Java is one of the powerful mechanism to handle the runtime
errors so that the normal flow of the application can be maintained.
In this section, we will learn about Java exceptions, it's types, and the difference between
checked and unchecked exceptions.
What is Exception in Java?
In Java, an exception is an event that occurs during the execution of a program that disrupts
the normal flow of instructions. These exceptions can occur for various reasons, such as
invalid user input, file not found, or division by zero. When an exception occurs, it is typically
represented by an object of a subclass of the java.lang.Exception class.
What is Exception Handling?
Exception Handling is a mechanism to handle runtime errors such as
ClassNotFoundException, IOException, SQLException, RemoteException, etc.
Hierarchy of Java Exception classes
The java.lang.Throwable class is the root class of Java Exception hierarchy inherited by two
subclasses: Exception and Error. The hierarchy of Java Exception classes is given below:
Types of Java Exceptions
In Java, exceptions are categorized into two main types: checked exceptions and
unchecked exceptions. Additionally, there is a third category known as errors. Let's delve
into each of these types:
1. Checked Exception
2. Unchecked Exception
3. Error
Types of Java Exceptions
In Java, exceptions are categorized into two main types: checked exceptions and
unchecked exceptions. Additionally, there is a third category known as errors. Let's delve
into each of these types:
1. Checked Exception
2. Unchecked Exception
3. Error
1. Checked Exceptions
Checked exceptions are the exceptions that are checked at compile-time. This means that
the compiler verifies that the code handles these exceptions either by catching them or
declaring them in the method signature using the throws keyword. Examples of checked
exceptions include:
IOException: An exception is thrown when an input/output operation fails, such as when
reading from or writing to a file.
SQLException: It is thrown when an error occurs while accessing a database.
ParseException: Indicates a problem while parsing a string into another data type, such as
parsing a date.
ClassNotFoundException: It is thrown when an application tries to load a class through its
string name using methods like Class.forName(), but the class with the specified name
cannot be found in the classpath.
2. Unchecked Exceptions (Runtime Exceptions)
Unchecked exceptions, also known as runtime exceptions, are not checked at compile-time.
These exceptions usually occur due to programming errors, such as logic errors or incorrect
assumptions in the code. They do not need to be declared in the method signature using
the throws keyword, making it optional to handle them. Examples of unchecked exceptions
include:
NullPointerException: It is thrown when trying to access or call a method on an object
reference that is null.
ArrayIndexOutOfBoundsException: It occurs when we try to access an array element
with an invalid index.
ArithmeticException: It is thrown when an arithmetic operation fails, such as division by
zero.
IllegalArgumentException: It indicates that a method has been passed an illegal or
inappropriate argument.
3. Errors
Errors represent exceptional conditions that are not expected to be caught under normal
circumstances. They are typically caused by issues outside the control of the application,
such as system failures or resource exhaustion. Errors are not meant to be caught or
handled by application code. Examples of errors include:
OutOfMemoryError: It occurs when the Java Virtual Machine (JVM) cannot allocate
enough memory for the application.
StackOverflowError: It is thrown when the stack memory is exhausted due to excessive
recursion.
NoClassDefFoundError: It indicates that the JVM cannot find the definition of a class that
was available at compile-time.
Understanding the different types of exceptions in Java is crucial for writing robust and
reliable code. By handling exceptions appropriately, you can improve the resilience of your
applications and provide better user experiences.hierarchy of exception handling
Difference between Checked and Unchecked Exceptions
Here are the key differences between checked exceptions, unchecked exceptions (runtime
exceptions), and errors in Java:
1. Checked Exceptions:
Compile-time Check: Checked exceptions are checked at compile-time by the Java
compiler. This means that the compiler ensures that these exceptions are either caught or
declared in the method signature using the throws keyword.
Examples: Examples of checked exceptions include IOException, SQLException,
ParseException, etc.
Forced Handling: Checked exceptions enforce explicit handling, either by catching them or
declaring them to be thrown. This helps in improving code reliability and robustness.
Recovery Possible: Checked exceptions typically represent recoverable conditions, such
as file not found or database connection failure, where the application may take corrective
action.
2. Unchecked Exceptions (Runtime Exceptions):
Not Checked at Compile-time: Unlike checked exceptions, unchecked exceptions are not
checked at compile-time. This means that the compiler does not enforce handling of
unchecked exceptions.
Examples: Examples of unchecked exceptions include NullPointerException,
ArrayIndexOutOfBoundsException, ArithmeticException, etc.
Runtime Errors: Unchecked exceptions often represent programming errors or unexpected
conditions during runtime, such as null references or array index out of bounds.
Optional Handling: Handling of unchecked exceptions is optional. While it's good practice
to handle them for robustness, it's not mandatory.
3. Errors:
Not Meant for Handling: Errors represent exceptional conditions that are typically beyond
the control of the application and are not meant to be caught or handled by application
code.
Examples: Examples of errors include OutOfMemoryError, StackOverflowError,
NoClassDefFoundError, etc.
Critical Conditions: Errors usually indicate critical conditions, such as JVM failures or
system resource exhaustion, where the application cannot recover.
Java Exception Keywords
Java provides five keywords that are used to handle the exception. The following table
describes each.
Keyword Description
The "try" keyword is used to specify a block
where we should place an exception code. It
try
means we can't use try block alone. The try block
must be followed by either catch or finally.
The "catch" block is used to handle the
exception. It must be preceded by try block which
catch
means we can't use catch block alone. It can be
followed by finally block later.
The "finally" block is used to execute the
finally necessary code of the program. It is executed
whether an exception is handled or not.
The "throw" keyword is used to throw an
throw
exception.
The "throws" keyword is used to declare
exceptions. It specifies that there may occur an
throws exception in the method. It doesn't throw an
exception. It is always used with method
signature.
The try-catch Block
One of the primary mechanisms for handling exceptions in Java is the try-catch block. The
try block contains the code that may throw an exception, and the catch block is used to
handle the exception if it occurs. Here's a basic example:
1. try {
2. // Code that may throw an exception
3. } catch (ExceptionType e) {
4. // Exception handling code
5. }
6.
Handling Multiple Exceptions
You can handle multiple types of exceptions by providing multiple catch blocks, each
catching a different type of exception. This allows you to tailor your exception handling logic
based on the specific type of exception thrown. Here's an example:
1. try {
2. // Code that may throw an exception
3. } catch (IOException e) {
4. // Handle IOException
5. } catch (NumberFormatException e) {
6. // Handle NumberFormatException
7. } catch (Exception e) {
8. // Handle any other exceptions
9. }
10.
The finally Block
In addition to try and catch, Java also provides a finally block, which allows you to execute
cleanup code, such as closing resources, regardless of whether an exception occurs or not.
The finally block is typically used to release resources that were acquired in the try block.
Here's an example:
1. try {
2. // Code that may throw an exception
3. } catch (Exception e) {
4. // Exception handling code
5. } finally {
6. // Cleanup code
7. }
8.
Java Exception Handling Example
Let's see an example of Java Exception Handling in which we are using a try-catch
statement to handle the exception.
JavaExceptionExample.java
1. public class JavaExceptionExample{
2. public static void main(String args[]){
3. try{
4. //code that may raise exception
5. int data=100/0;
6. }catch(ArithmeticException e){System.out.println(e);}
7. //rest code of the program
8. System.out.println("rest of the code...");
9. }
10. }
Output:
Exception in thread main java.lang.ArithmeticException:/ by zero
rest of the code..
.
In the above example, 100/0 raises an ArithmeticException which is handled by a try-catch
block.
Common Scenarios of Java Exceptions
There are given some scenarios where unchecked exceptions may occur. They are as
follows:
1) A scenario where ArithmeticException occurs
If we divide any number by zero, there occurs an ArithmeticException.
1. int a=50/0;//ArithmeticException
Here's a simple Java code example where an ArithmeticException occurs:
File Name: ArithmeticExceptionExample.java
1. public class ArithmeticExceptionExample {
2. public static void main(String[] args) {
3. int dividend = 10;
4. int divisor = 0;
5. try {
6. int result = dividend / divisor; // Division by zero
7. System.out.println("Result: " + result);
8. } catch (ArithmeticException e) {
9. System.out.println("Error: Division by zero is not allowed.");
10. // Additional error handling code can be added here
11. }
12. }
13. }
Output:
Error: Division by zero is not allowed.
2) A scenario where NullPointerException occurs
If we have a null value in any variable, performing any operation on the variable throws a
NullPointerException.
1. String s=null;
2. System.out.println(s.length());//NullPointerException
Here's a Java code example where a NullPointerException occurs:
File Name: NullPointerExceptionExample.java
1. public class NullPointerExceptionExample {
2. public static void main(String[] args) {
3. String str = null; // Initializing a String variable to null
4. try {
5. int length = str.length(); // Attempting to call a method on a null reference
6. System.out.println("Length of the string: " + length);
7. } catch (NullPointerException e) {
8. System.out.println("Error: Null reference encountered.");
9. // Additional error handling code can be added here
10. }
11. }
12. }
Output:
Error: Null reference encountered.
3) A scenario where NumberFormatException occurs
If the formatting of any variable or number is mismatched, it may result into
NumberFormatException. Suppose we have a string variable that has characters;
converting this variable into digit will cause NumberFormatException.
1. String s="abc";
2. int i=Integer.parseInt(s);//NumberFormatException
Here's a Java code example where a NumberFormatException occurs:
File Name: NumberFormatExceptionExample.java
1. public class NumberFormatExceptionExample {
2. public static void main(String[] args) {
3. String str = "abc"; // Initializing a String with non-numeric characters
4. try {
5. int num = Integer.parseInt(str); // Attempting to parse a non-numeric string to an integer
6. System.out.println("Parsed number: " + num);
7. } catch (NumberFormatException e) {
8. System.out.println("Error: Unable to parse the string as an integer.");
9. // Additional error handling code can be added here
10. }
11. }
12. }
Output:
Error: Unable to parse the string as an integer.
4) A scenario where ArrayIndexOutOfBoundsException occurs
When an array exceeds to it's size, the ArrayIndexOutOfBoundsException occurs. there
may be other reasons to occur ArrayIndexOutOfBoundsException. Consider the following
statements.
1. int a[]=new int[5];
2. a[10]=50; //ArrayIndexOutOfBoundsException
Here's a Java code example where an ArrayIndexOutOfBoundsException occurs:
File Name: ArrayIndexOutOfBoundsExceptionExample.java
1. public class ArrayIndexOutOfBoundsExceptionExample {
2. public static void main(String[] args) {
3. int[] numbers = {1, 2, 3, 4, 5}; // Initializing an array with 5 elements
4. try {
5. int index = 10; // Accessing an index that is out of bounds
6. int value = numbers[index]; // Attempting to access an element at an invalid index
7. System.out.println("Value at index " + index + ": " + value);
8. } catch (ArrayIndexOutOfBoundsException e) {
9. System.out.println("Error: Index is out of bounds.");
10. // Additional error handling code can be added here
11. }
12. }
13. }
Output:
Error: Index is out of bounds.
Java try-catch block
Java try block
Java try block is used to enclose the code that might throw an exception. It must be used
within the method.
If an exception occurs at the particular statement in the try block, the rest of the block code
will not execute. So, it is recommended not to keep the code in try block that will not throw
an exception.
Java try block must be followed by either catch or finally block.
Syntax of Java try-catch
1. try{
2. //code that may throw an exception
3. }catch(Exception_class_Name ref){}
Syntax of try-finally block
1. try{
2. //code that may throw an exception
3. }finally{}
Java catch block
Java catch block is used to handle the Exception by declaring the type of exception within
the parameter. The declared exception must be the parent class exception ( i.e., Exception)
or the generated exception type. However, the good approach is to declare the generated
type of exception.
The catch block must be used after the try block only. You can use multiple catch block with
a single try block.
Internal Working of Java try-catch block
The JVM firstly checks whether the exception is handled or not. If exception is not handled,
JVM provides a default exception handler that performs the following tasks:
o Prints out exception description.
o Prints the stack trace (Hierarchy of methods where the exception occurred).
o Causes the program to terminate.
But if the application programmer handles the exception, the normal flow of the application
is maintained, i.e., rest of the code is executed.
Problem without exception handling
Let's try to understand the problem if we don't use a try-catch block.
Example 1
TryCatchExample1.java
1. public class TryCatchExample1 {
2.
3. public static void main(String[] args) {
4.
5. int data=50/0; //may throw exception
6.
7. System.out.println("rest of the code");
8.
9. }
10.
11. }
Output:
Exception in thread "main" java.lang.ArithmeticException: / by zero
Solution by exception handling
Let's see the solution of the above problem by a java try-catch block.
Example 2
TryCatchExample2.java
1. public class TryCatchExample2 {
2.
3. public static void main(String[] args) {
4. try
5. {
6. int data=50/0; //may throw exception
7. }
8. //handling the exception
9. catch(ArithmeticException e)
10. {
11. System.out.println(e);
12. }
13. System.out.println("rest of the code");
14. }
15.
16. }
Output:
java.lang.ArithmeticException: / by zero
rest of the code
Example 3
In this example, we also kept the code in a try block that will not throw an exception.
TryCatchExample3.java
1. public class TryCatchExample3 {
2.
3. public static void main(String[] args) {
4. try
5. {
6. int data=50/0; //may throw exception
7. // if exception occurs, the remaining statement will not exceute
8. System.out.println("rest of the code");
9. }
10. // handling the exception
11. catch(ArithmeticException e)
12. {
13. System.out.println(e);
14. }
15.
16. }
17.
18. }
Output:
java.lang.ArithmeticException: / by zero
Example 4
Here, we handle the exception using the parent class exception.
TryCatchExample4.java
1. public class TryCatchExample4 {
2.
3. public static void main(String[] args) {
4. try
5. {
6. int data=50/0; //may throw exception
7. }
8. // handling the exception by using Exception class
9. catch(Exception e)
10. {
11. System.out.println(e);
12. }
13. System.out.println("rest of the code");
14. }
15.
16. }
Output:
java.lang.ArithmeticException: / by zero
rest of the code
Let's see an example to print a custom message on exception.
TryCatchExample5.java
1. public class TryCatchExample5 {
2.
3. public static void main(String[] args) {
4. try
5. {
6. int data=50/0; //may throw exception
7. }
8. // handling the exception
9. catch(Exception e)
10. {
11. // displaying the custom message
12. System.out.println("Can't divided by zero");
13. }
14. }
15.
16. }
Output:
Can't divided by zero
Example 6
Let's see an example to resolve the exception in a catch block.
TryCatchExample6.java
1. public class TryCatchExample6 {
2.
3. public static void main(String[] args) {
4. int i=50;
5. int j=0;
6. int data;
7. try
8. {
9. data=i/j; //may throw exception
10. }
11. // handling the exception
12. catch(Exception e)
13. {
14. // resolving the exception in catch block
15. System.out.println(i/(j+2));
16. }
17. }
18. }
Output:
25
Example 7
In this example, along with try block, we also enclose exception code in a catch block.
TryCatchExample7.java
1. public class TryCatchExample7 {
2.
3. public static void main(String[] args) {
4.
5. try
6. {
7. int data1=50/0; //may throw exception
8.
9. }
10. // handling the exception
11. catch(Exception e)
12. {
13. // generating the exception in catch block
14. int data2=50/0; //may throw exception
15.
16. }
17. System.out.println("rest of the code");
18. }
19. }
Output:
Exception in thread "main" java.lang.ArithmeticException: / by zero
Example 8
In this example, we handle the generated exception (Arithmetic Exception) with a different
type of exception class (ArrayIndexOutOfBoundsException).
TryCatchExample8.java
1. public class TryCatchExample8 {
2.
3. public static void main(String[] args) {
4. try
5. {
6. int data=50/0; //may throw exception
7.
8. }
9. // try to handle the ArithmeticException using ArrayIndexOutOfBoundsException
10. catch(ArrayIndexOutOfBoundsException e)
11. {
12. System.out.println(e);
13. }
14. System.out.println("rest of the code");
15. }
16.
17. }
Output:
Exception in thread "main" java.lang.ArithmeticException: / by zero
Example 9
Let's see an example to handle another unchecked exception.
TryCatchExample9.java
1. public class TryCatchExample9 {
2.
3. public static void main(String[] args) {
4. try
5. {
6. int arr[]= {1,3,5,7};
7. System.out.println(arr[10]); //may throw exception
8. }
9. // handling the array exception
10. catch(ArrayIndexOutOfBoundsException e)
11. {
12. System.out.println(e);
13. }
14. System.out.println("rest of the code");
15. }
16.
17. }
Output:
java.lang.ArrayIndexOutOfBoundsException: 10
rest of the code
Example 10
Let's see an example to handle checked exception.
TryCatchExample10.java
1. import java.io.FileNotFoundException;
2. import java.io.PrintWriter;
3.
4. public class TryCatchExample10 {
5.
6. public static void main(String[] args) {
7.
8.
9. PrintWriter pw;
10. try {
11. pw = new PrintWriter("jtp.txt"); //may throw exception
12. pw.println("saved");
13. }
14. // providing the checked exception handler
15. catch (FileNotFoundException e) {
16.
17. System.out.println(e);
18. }
19. System.out.println("File saved successfully");
20. }
21. }
Output:
File saved successfully
Java Catch Multiple Exceptions
Java Multi-catch block
A try block can be followed by one or more catch blocks. Each catch block must contain a
different exception handler. So, if you have to perform different tasks at the occurrence of
different exceptions, use java multi-catch block.
Points to remember
o At a time only one exception occurs and at a time only one catch block is executed.
o All catch blocks must be ordered from most specific to most general, i.e. catch for
ArithmeticException must come before catch for Exception.
Flowchart of Multi-catch Block
Example 1
Let's see a simple example of java multi-catch block.
MultipleCatchBlock1.java
1. public class MultipleCatchBlock1 {
2.
3. public static void main(String[] args) {
4.
5. try{
6. int a[]=new int[5];
7. a[5]=30/0;
8. }
9. catch(ArithmeticException e)
10. {
11. System.out.println("Arithmetic Exception occurs");
12. }
13. catch(ArrayIndexOutOfBoundsException e)
14. {
15. System.out.println("ArrayIndexOutOfBounds Exception occurs");
16. }
17. catch(Exception e)
18. {
19. System.out.println("Parent Exception occurs");
20. }
21. System.out.println("rest of the code");
22. }
23. }
Output:
Arithmetic Exception occurs
rest of the code
Example 2
MultipleCatchBlock2.java
1. public class MultipleCatchBlock2 {
2.
3. public static void main(String[] args) {
4.
5. try{
6. int a[]=new int[5];
7.
8. System.out.println(a[10]);
9. }
10. catch(ArithmeticException e)
11. {
12. System.out.println("Arithmetic Exception occurs");
13. }
14. catch(ArrayIndexOutOfBoundsException e)
15. {
16. System.out.println("ArrayIndexOutOfBounds Exception occurs");
17. }
18. catch(Exception e)
19. {
20. System.out.println("Parent Exception occurs");
21. }
22. System.out.println("rest of the code");
23. }
24. }
Output:
ArrayIndexOutOfBounds Exception occurs
rest of the code
In this example, try block contains two exceptions. But at a time only one exception occurs
and its corresponding catch block is executed.
Example 3
In this example, we generate NullPointerException, but didn't provide the corresponding
exception type. In such case, the catch block containing the parent exception
class Exception will invoked.
MultipleCatchBlock4.java
1. public class MultipleCatchBlock4 {
2.
3. public static void main(String[] args) {
4.
5. try{
6. String s=null;
7. System.out.println(s.length());
8. }
9. catch(ArithmeticException e)
10. {
11. System.out.println("Arithmetic Exception occurs");
12. }
13. catch(ArrayIndexOutOfBoundsException e)
14. {
15. System.out.println("ArrayIndexOutOfBounds Exception occurs");
16. }
17. catch(Exception e)
18. {
19. System.out.println("Parent Exception occurs");
20. }
21. System.out.println("rest of the code");
22. }
23. }
Output:
Parent Exception occurs
rest of the code
Example 5
Let's see an example, to handle the exception without maintaining the order of exceptions
(i.e. from most specific to most general).
MultipleCatchBlock5.java
1. class MultipleCatchBlock5{
2. public static void main(String args[]){
3. try{
4. int a[]=new int[5];
5. a[5]=30/0;
6. }
7. catch(Exception e){System.out.println("common task completed");}
8. catch(ArithmeticException e){System.out.println("task1 is completed");}
9. catch(ArrayIndexOutOfBoundsException e){System.out.println("task 2 completed");}
10. System.out.println("rest of the code...");
11. }
12. }
Output:
Compile-time error
Java Nested try block
In Java, using a try block inside another try block is permitted. It is called as nested try
block. Every statement that we enter a statement in try block, context of that exception is
pushed onto the stack.
For example, the inner try block can be used to
handle ArrayIndexOutOfBoundsException while the outer try block can handle
the ArithemeticException (division by zero).
Why use nested try block
Sometimes a situation may arise where a part of a block may cause one error and the entire
block itself may cause another error. In such cases, exception handlers have to be nested.
Syntax:
1. ....
2. //main try block
3. try
4. {
5. statement 1;
6. statement 2;
7. //try catch block within another try block
8. try
9. {
10. statement 3;
11. statement 4;
12. //try catch block within nested try block
13. try
14. {
15. statement 5;
16. statement 6;
17. }
18. catch(Exception e2)
19. {
20. //exception message
21. }
22.
23. }
24. catch(Exception e1)
25. {
26. //exception message
27. }
28. }
29. //catch block of parent (outer) try block
30. catch(Exception e3)
31. {
32. //exception message
33. }
34. ....
Java Nested try Example
Example 1
Let's see an example where we place a try block within another try block for two different
exceptions.