In this article, I will write about exception handling in Java, which will help you to get the good knowledge of the topic.
Firstly,
What is an exception?
An exception is an unwanted or unexpected event that occurs during the execution of the program, that disrupts the flow of the program. It can occur for various reasons:
A user has entered an invalid data.
File not found.
Hardware failure.
A network connection has been lost in the middle of communication.
Database server that is down.
Now you might be wondering, an error does the same thing, but it is a lot more different.
Difference between error and exception
Error: An error is a state at which the computer program cannot recover and stays in a non-executable mode or sometimes collapses from normal execution.
Errors are always of unchecked type, as compiler do not have any knowledge about its occurrence. Errors always occur in the runtime environment.
Exception: An exception is an unexpected event that may occur during the program's compile time or run-time. The exceptions are classified as the "checked" and "unchecked". Unchecked exceptions are not in knowledge of compiler as they occur during runtime whereas, the compiler has the knowledge about checked exceptions as they are known to compiler during compile time.
Exception Error
Time of Occurrence | Occur at compile time or runtime. | Occur at runtime. |
---|---|---|
Recovery | Programs are recoverable from exceptions by handling them appropriately using try/catch block or throw keyword in java. | Programs are irrecoverable from Errors once they occur. |
Package | Exceptions are defined in java.lang.Exception | Errors belong to the java.lang.Error |
Checked/Unchecked | Both checked and unchecked. | Errors belong to the Unchecked type. |
Cause | Caused by application/program. | Caused by the environment in which the program runs. |
Examples | Checked Exception examples are IOException, SQLException, and Unchecked Exception examples are NullPointerException, ArrayIndexOutOfBoundsException. | java.lang.OutOfMemoryError, java.lang.StackOverflowError |
Exceptions Hierarchy
All exception and error types are subclasses of class Throwable, which is the base class of hierarchy. One branch is headed by Error and other by Exception.
Types of Exceptions:
1. Built-in Exceptions
Built-in Exceptions | Description |
ArithmeticException | It is thrown when an exceptional condition has occurred in an arithmetic operation. |
ArrayIndexOutOfBoundsException | It is thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array. |
ClassNotFoundException | This exception is raised when we try to access a class whose definition is not found. |
FileNotFoundException | An exception that is raised when a file is not accessible or does not open. |
IOException | It is thrown when an input-output operation is failed or interrupted. |
InterruptedException | It is thrown when a thread is waiting, sleeping, or doing some processing, and it is interrupted. |
NoSuchFieldException | It is thrown when a class does not contain the field (or variable) specified. |
2. User-defined Exceptions:
Sometimes, the built-in exceptions in java are not able to describe a certain situation. In such cases, a user can also create exceptions which are called 'User-Defined Exceptions'.
Important points:
A user-defined exception must extend Exception class.
It is thrown using throw keyword.
Why handle Java Exception?
We handle exceptions in java to make sure the program executes properly without any halt, which occurs when an exception is raised. They may be minor exceptions but can cause a problem in executions of the program, hence it become necessary to handle java exceptions. If java exceptions are not handled, programs may crash, and execution is halted in between.
What is Exception Handling in java?
Exception handling in java is a mechanism to handle unwanted interruptions like exceptions and continue with the normal flow of the program.
Exception Handling Methods
How to handle exceptions in java?
Handling an exception is very important, else it leads to system failure, but how do you handle exceptions.
Java provides various methods to handle the Exceptions like:
1.try-catch :
The try block contains a set of statements where an exception can occur. It is always followed by a catch block, which handles the exception that occurs in the associated try block. Example
public static void main(String[] args) {
try { int divideByZero = 5 / 0; System.out.println("Exception in catch block "); } catch (ArithmeticException e) { System.out.println("ArithmeticException => " + e.getMessage()); } } } |
Output:
ArithmeticException => / by zero
In the above example, notice the line,
int divideByZero = 5/0;
Here, we are trying to divide a number by zero. In this case, an exception occurs. That's why we enclosed this code inside the try block.
When the program encounters this code, ArithmeticException occurs which is caught by the catch block and executes the code inside the catch block.
The catch block is only executed if there exists an exception inside the try block.
Important: In java, we can use a try block without a catch block. However, we cannot use a catch block without a try block. |
2.try...finally block:
We can use try block with a finally block. In this case, the finally block is always executed whether there is an exception inside the try block or not. Example:
class Main { public static void main(String[] args) { try { int divideByZero = 5 / 0; } finally { System.out.println("Finally block is always executed"); } } } |
Output:
Finally block is always executed
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Methods.TryCatch.main(TryCatch.java:9)
In the above example, code inside the try block is causing an exception.
However, the code inside the finally block is executed irrespective of the exception.
3. try...catch...finally block:
We can also use finally block after the try..catch block. For example
public static void main (String args[]) { //try block try { System.out.println ("::Try Block::"); int data = 125 / 5; System.out.println ("Result:" + data); } //catch block catch (NullPointerException e) { System.out.println ("::Catch Block::"); System.out.println (e); } //finally block finally { System.out.println (":: Finally Block::"); System.out.println ("No Exception::finally block executed"); }
} |
Output:
::Try Block::
Result:25
:: Finally Block::
No Exception::finally block executed
In the above example, a valid operation is performed in try block and hence no exception is thrown. Therefore, the control is not passed to catch from try but to finally block.
4. Multiple Catch blocks:
For each try block, there can be zero or more catch blocks. Multiple catch blocks allow us to handle each exception differently.
The argument type of each catch block indicates the type of exception that can be handled by it. For example
public class MultipleCatch {
public int[] arr = new int[10]; public void writeList() { try { arr[10] = 11; }
catch (NumberFormatException e1) { System.out.println("NumberFormatException => " + e1.getMessage()); }
catch (IndexOutOfBoundsException e2) { System.out.println("IndexOutOfBoundsException => " + e2.getMessage()); } }
public static void main(String[] args) { MultipleCatch list = new MultipleCatch(); list.writeList(); } } |
Output:
IndexOutOfBoundsException => Index 10 out of bounds for length 10
In the above example, we have created an integer array of size 10. Since the array index starts from 0, the last element of the array is at arr[9].
We are trying to assign a value to the index 10. Hence, IndexOutOfBoundException occurs.
When an exception occurs in the try block, the exception is thrown to the first catch block. The first catch block does not handle the exception, so it is passed to the next catch block. The second catch block is the appropriate exception handler. Hence, it is executed.
5. Nested try-catch:
A try block inside another try block is called nested try block. We need this structure when a piece of code contained in a try code may be such that some lines raise certain exceptions and another piece of code raises a completely different exception.
In this case of nested try blocks, first the innermost try block is executed and the exception is handled. If the innermost try block does not have a matching catch block, then it is propagated one level up to its parent try block.
public static void main(String args[]){ //Main try block try{ //try block1 try{ System.out.println("Try Block1"); int num =15/0; System.out.println(num); } catch(ArithmeticException e1){ System.out.println("Block1 Exception: e1"); } //try block2 try{ System.out.println("Try Block2"); int num =100/0; System.out.println(num); } catch(ArrayIndexOutOfBoundsException e2){ System.out.println("Block2 Exception: e2"); } System.out.println("General statement after Block1 and Block2"); } catch(ArithmeticException e3){ System.out.println("Main Block Arithmetic Exception"); } catch(ArrayIndexOutOfBoundsException e4){ System.out.println("Main Block ArrayIndexOutOfBoundsException"); } catch(Exception e5){ System.out.println("Main Block General Exception"); } System.out.println("Code after Nested Try Block"); } } |
Output:
Try Block1
Block1 Exception: e1
Try Block2
Main Block Arithmetic Exception
Code after Nested Try Block
In the above program, we have two try blocks enclosed in the main try block. Both the inner try blocks have a code that raises the ArithmeticException. But we have provided a matching catch block only for the first block and not for the second try block.
Hence the second block propagates its exception to the main try block and then handles it.
6. throw an exception:
The throw keyword is used to explicitly throw a single exception.
When an exception is thrown, the flow of program execution transfers from the try block to the catch block. Using the throw keyword, we can throw the checked or unchecked exceptions. The throw keyword is also used to throw custom exceptions. For example
public class Throw {
public static void divideByZero() { throw new ArithmeticException("Trying to divide by 0"); } public static void main(String[] args) { divideByZero(); } } |
Output:
Exception in thread "main" java.lang.ArithmeticException: Trying to divide by 0
at Methods.Throw.divideByZero(Throw.java:6)
at Methods.Throw.main(Throw.java:10)
In this example we are throwing an ArithmeticException.
7. throws clause:
The declaration of exception using the "throws" keyword tells that there may be an exception specified after the "throws" keyword and we need a corresponding handler code for this exception to maintain the proper flow of the program. For example
public class Throws { public static void checkAge(int age) throws ArithmeticException { if (age < 18) { throw new ArithmeticException("Access denied - You must be at least 18 years old."); } else { System.out.println("Access granted - You are old enough!"); } } public static void main(String[] args) { checkAge(15); } } |
Output:
Exception in thread "main" java.lang.ArithmeticException: Access denied - You must be at least 18 years old.
at Methods.Throws.checkAge(Throws.java:6)
at Methods.Throws.main(Throws.java:14)
In the above program, we declare Arithmetic Exception using the throws keyword.
Difference between throw and throws:
throw | throws |
1.Used to explicitly throw an exception. | 1.Used to declare an exception. |
2. Checked exceptions cannot be propagated using throw only. | 2. Checked exceptions can be propagated. |
3.Followed by an instance. | 3.Followed by a class. |
4.Used within a method. | 4.Used with a method signature. |
5. Cannot throw multiple exceptions. | 5.Can declare multiple exceptions. |
throws keyword Vs try...catch:
There are several methods that can cause exceptions. Writing try...catch for each method will be tedious and code becomes long.
Thus, declaring an exception with the throws keyword in the method signature seems to be a viable solution.
Finally, this brings us to the end of my blog on Exception Handling in Java. I hope you found this blog informative.