Why Exception Handling?
To understand Exception Handling first, we should know why we need exception handling.
When we write programs as a part of an application, we have to visualize the challenges that might terminate the normal execution of the code. Once we know we can take preventive measures across this problem.
What is an Exception?
In normal words, the exception is an abnormal event or runtime error that occurs during the execution of a program that interrupts the normal flow of instructions.
The ability of a program to intercept run-time errors, take corrective measures, and continue execution is referred to as exception handling.
Various situations when an exception could occur,
-
Attempting to access a file that doesn't exist results in FILENOTFOUND Exception.
-
Performing some mathematical operations that are not permitted results in an ARITHMETIC exception.
-
Inserting an element into an array that is not in its bounds results in ARRAYOUTOFBOUND Exception.
-
Declaring an array with negative(-ve) values results in NUMBERFORMAT Exception.
Example: (Uncaught Exception)
- class Demo {
- public static void main(String[] args) {
- int x = 0;
- int y = 50 / x;
- System.out.println(y);
- }
- }
Although the above program will compile successfully when you execute it the Java Runtime System will generate an exception and displays the following output.
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:13)
So how to handle this abnormal execution of the program will be discussed below.
Handling Exception
As in the above code snippet, the code compiles successfully but the execution of the code results in runtime exception or abnormal termination of the code.
We can handle the exception by using try-catch-finally block or throw keyword or throw keyword. To understand how to use this block will take the same example as above.
Example: (Uncaught Exception)
- class Demo {
- public static void main(String[] args) {
- int x = 0;
- int y = 50 / x;
- System.out.println(y);
- }
- }
This code will throw an arithmetic Exception(Division by zero Exception) at runtime. So to overcome this abnormal termination we will use the try-catch-finally block in this example.
Example
- class Demo {
- public static void main(String[] args) {
- try {
- int x = 20;
- int y = 50 / x;
- System.out.println("This will be bypassed.");
- } catch (ArithmeticException e) {
- System.out.println("Division By Zero.");
- } finally {
- System.out.println("Program Executed Successfully.");
- }
- }
- }
The above program will restrict abnormal termination of the program with the following output,
Division By Zero.
Program Executed Successfully.
Multiple Catch Statements
A single block of code can raise more than one exception in a program, we can specify two or more catch clauses each catching a different type of exception.
When an exception is thrown by Java Runtime Environment, each statement is inspected in order and the first one whose type matches that of the type of exception is executed.
After one catch statement executes, the others are bypassed and execution continues after the try-catch block.
This scenario can be explained by using an example;
Example
- class Demo {
- public static void main(String[] args) {
- try {
- int len = args.length;
- System.out.println(len);
- int y = 50 / len;
- int[] arr = {
- len
- };
- } catch (ArithmeticException e) {
- System.out.println("Divide by Zero " + e);
- } catch (ArrayIndexOutOfBoundsException e) {
- System.out.println("Array Index Out Of Bounds " + e);
- }
- System.out.println("After try/catch blocks.");
- }
- }
Passing 0 as a command-line argument will result in the following,
Output
0
Divide by Zero java.lang.ArithmeticException: / by zero
After try/catch blocks.
Whenever we are using multiple catch statements, it is important to remember that exception subclasses must come before any of their exception superclasses. This is because a catch statement that uses a superclass will catch exceptions as well as exceptions of the subclass.
Thus, a subclass exception would be reached if it came after its superclass that manifested as an unreachable code error.
This scenario can be explained by using an example;
Example
- class Demo {
- public static void main(String[] args) {
- try {
- int x = 0;
- int y = 50 / x;
- } catch (Exception e) {
- System.out.println("Generic Exception Caught " + e);
- }
-
-
- catch (ArithmeticException e) {
- System.out.println("This will be never reached. ");
- }
- }
- }
Output
Main.java:24: error: exception ArithmeticException has already been caught
catch(ArithmeticException e)
This program will result in an Unreachable code at line:12 because Arithmetic Exception is a subclass of Exception Class, and when a program executes it executes in order so at first Superclass Exception is caught that has Subclass Arithmetic Exception in it by default. Thus resulting in an Unreachable code.
When you use multiple catch statements, it is important to remember that exception subclasses must come before any of their exception superclasses. This is because a catch statement that uses superclasses will catch exceptions of that type as well as exceptions of its subclasses.
Thus, a subclass exception would be reached if it came after its superclass that manifested as an unreachable code error.
Nested Try Statements
The try statements can be nested, if an inner try statement doesn’t have a catch handler for a particular exception, the outer blocks catch handler will handle the exception.
This continues until one of the catch statements succeeds until all of the nested try statements are exhausted.
Note
If no catch statement matches, then JRE will handle the exception.
Using throw
By using the throw keyword, we can either throw an exception to either catch block exceptional handler or calling method. A system-generated exception is thrown automatically, at times you want to throw the exceptions explicitly which can be done using the throw keyword.
General Form: throw Throwable Instance
Here, a Throwable instance must be an object of type Throwable or a subclass of throwable
This scenario can be explained by using an example,
Example
- class Demo {
- public static void main(String[] args) {
- try {
- int age = Integer.parseInt(args[0]);
- if (age < 18) throw new ArithmeticException();
- else
- if (age > 60) throw new ArithmeticException("Person is retired");
- } catch (ArithmeticException e) {
- System.out.println(e);
- }
- System.out.println("After try/catch blocks.");
- }
- }
Passing 10 as a command-line argument will result in the following code
Output
java.lang.ArithmeticException
After try/catch blocks.
Using throws
Some class or method is capable of causing an exception that it doesn’t handle. Then, it must specify this behavior so that callers of the method can guard themselves against that exception.
While declaring such methods, you have to specify what type of exception it may throw by using the throws keyword.
A throws clause specifies a comma-separated list of exception types that a method might throw.
General Form: type method-name(parameter) throws exception-list
This scenario can be explained by using an example,
Example
- class Demo {
- static void throwOne() throws IOException {
- System.out.println("Inside throwOne().");
- thrownew IOException();
- }
- public static void main(String[] args) {
- try {
- throwOne();
- } catch (IOException e) {
- System.out.println("Exception Caught " + e);
- }
- System.out.println("After try/catch blocks.");
- }
- }
This code will result in the following,
Output
Exception Caught IOException
After try/catch blocks.
Using finally
This block is optional finally, the block should be immediately proceeded by either try or catch block. When an exception occurs the execution of the program takes a non-linear path.
This block is executed always after the execution of the code block. Is more used to close the connection. The finally block is guaranteed to execute in all circumstances.
This scenario can be explained by using an example,
- class Demo {
- public static void main(String[] args) {
- try {
- int x = 25;
- int y = 50 / x;
- System.out.println("This will be bypassed.");
- } catch (ArithmeticException e) {
- System.out.println("Division By Zero.");
- } finally
- {
- System.out.println("Program Executed Successfully.");
- }
- }
- }
The above program will restrict abnormal termination of the program with the following output;
This will be bypassed.
Program Executed Successfully.
Summary
Thus, coming towards the end of this article, we had learned much about Exception Handling and how to use them with Java.
What did we learn?
-
Why exception handling?
-
What is an exception?
- Handling Exceptions
- Multiple catch statements
- Nested try statements
- Using throw keyword
- Using throws keyword
- Using finally