Introduction to Exception Handling in Java
-
Last Updated: September 21, 2024
-
By: javahandson
-
Series
In this article, we will introduce Exception Handling in Java. We will also learn about the types of exceptions and the errors.
Exception Handling in Java helps to handle the exceptions raised while executing a program or an application. Suppose we are running a program and some exception is raised then our exception handling mechanism handles this exception gracefully and our program will not end abruptly.
An exception is an event that occurs during the execution of a program, disrupting its normal flow. Exceptions can occur due to coding or user-input problems. However, the one good thing about exceptions is that they can be handled.
There are 2 types of exceptions:
These are exceptions that are checked at compile-time. The programmer must handle these exceptions else the program will not be compiled and will get a compilation issue.
Checked exceptions hierarchy:
These are exceptions that occur while running a program and they are not checked at compile-time. These exceptions mainly occur because of logical flaws or incorrect data handling or we can say programming errors. We do not have to explicitly handle the unchecked exceptions, these will be handled by JVM.
If as a programmer we handle the unchecked exception that’s good but if we do not handle it explicitly then the current method where the exception is raised terminates abruptly and the control is passed to the caller method. Now if the caller method also does not handle the exception then the control moves further up until it either gets caught by a try-catch block or reaches the main thread.
If the unchecked exception is not caught at any point in the call stack, it eventually reaches the JVM’s default exception handler. The JVM prints the stack trace of the exception, providing information on where the exception occurred, what type of exception it was, and the sequence of method calls that led to it. After printing the stack trace, the JVM terminates the program.
Although it’s not required to handle the unchecked exceptions but it is a good practice to handle the common runtime exceptions and also as a developer, if we think a piece of code might throw a runtime exception in such scenarios it is good practice to handle the exceptions.
Unchecked exceptions hierarchy:
In the above section, we said many a time that the exception has to be handled to maintain the normal flow of the program. So how can we handle the exception?
The most common way to handle exceptions in Java is by using try-catch blocks. The code that might throw an exception is placed in the try block and if an exception occurs it is caught in the corresponding catch block.
We can have multiple catch blocks to handle different types of exceptions. Multiple catch blocks can be used if we need different handling strategies for different types of exceptions.
From Java 7 we can handle multiple exceptions in a single catch block by separating them with a pipe.
Write a program to handle the checked exception.
package com.javahandson; import java.io.FileReader; public class CheckedExceptions { public static void main(String[] args) { FileReader reader = new FileReader("file.txt"); reader.read(); reader.close(); } } Output: Exception in thread "main" java.lang.Error: Unresolved compilation problems: Unhandled exception type FileNotFoundException Unhandled exception type IOException Unhandled exception type IOException at com.javahandson.CheckedExceptions.main(CheckedExceptions.java)
The above program throws an IOException i.e. a checked exception and since it is not handled hence a compilation issue is raised and the program will not execute. In order to execute the program and handle the checked exception we should use the try-catch block like below.
package com.javahandson; import java.io.FileReader; import java.io.IOException; public class CheckedExceptions { public static void main(String[] args) { try { FileReader reader = new FileReader("file.txt"); reader.read(); reader.close(); } catch (IOException ioException) { System.out.println("Handle the IOException here"); } } } Output: Handle the IOException here
Write a program to handle the unchecked exception.
package com.javahandson; public class UncheckedExceptions { public static void main(String[] args) { int result = 10/0; System.out.println(result); } } Output: Exception in thread "main" java.lang.ArithmeticException: / by zero at com.javahandson.UncheckedExceptions.main(UncheckedExceptions.java)
The above program throws an ArithmeticException i.e. unchecked exception and even though we did not catch the exception still the program is compiled and executed. So we don’t have to catch the unchecked exceptions JVM will take care of it.
But if we don’t want the above program to end abruptly or we have some exception-handling strategy then we can use a try-catch block.
package com.javahandson; public class UncheckedExceptions { public static void main(String[] args) { int result = 0; try { result = 10/0; System.out.println("Result is : "+result); } catch (ArithmeticException arithmeticException) { System.err.println("Arithmetic exception is encountered"); result = 10/1; System.out.println("Result is : "+result); } } } Output: Arithmetic exception is encountered Result is : 10
Errors are problems that we should not try to catch or recover from. Errors are beyond the control of the programmer. Errors will mostly arise because of the environment in which the application is running. The JVM will throw errors if it faces some system-level failures like memory depletion, stack overflow issues or hardware issues etc. Errors in Java are part of the java.lang.Error class and its subclasses.
OutOfMemoryError: This exception is thrown when the JVM runs out of memory.
StackOverflowError: This exception is thrown when a method recurses too deeply and exceeds the stack size.
NoClassDefFoundError: This exception is thrown when the JVM cannot find a required class at runtime.
Write a program to throw the StackOverflowError while calculating a factorial.
package com.javahandson; public class StackOverflowErrorTest { public static void main(String[] args) { int result = factorial(5); System.out.println(result); } public static int factorial(int n) { // Recursive case return n * factorial(n - 1); } } Output: Exception in thread "main" java.lang.StackOverflowError at com.javahandson.StackOverflowErrorTest.factorial(StackOverflowErrorTest.java) at com.javahandson.StackOverflowErrorTest.factorial(StackOverflowErrorTest.java) at com.javahandson.StackOverflowErrorTest.factorial(StackOverflowErrorTest.java)
We can fix the StackOverflowError in the above scenario by adding a base condition. Without a base condition, the method will call itself indefinitely causing a stack overflow.
package com.javahandson; public class StackOverflowErrorTest { public static void main(String[] args) { int result = factorial(5); System.out.println("factorial of number : "+ result); } public static int factorial(int n) { // Base case: stop recursion when n reaches 1 if (n <= 1) { return 1; } // Recursive case return n * factorial(n - 1); } } Output: factorial of number : 120
So this is all about the introduction to Exception Handling in Java. We will go in-depth about exception handling in the next articles.
If you have any questions on this topic, please raise them in the comments section. If you liked this article then please share this post with your friends and colleagues.