Try, Catch and Finally in Java
Exception Handling, in programming, is the process by which we address the occurrence of exceptions, and thus prevent unexpected outcomes of our program.
An exception is an unpredicted condition, which can abrupt the flow of our program. We use Try, Catch, and Finally in Java Exception Handling. Try, Catch and Finally come in very handy for handling the occurrence of any exception, thus maintaining the flow and also debugging and logging the program.
What is an Exception?
Let us start with an example. Let's say we are dividing two numbers: a and b. If b has a value of 0, we know that the resultant value is not defined, so this is an exception.
The word exception is shorthand for the phrase exceptional event. In Java, an exception is an unanticipated condition that can occur while the execution of code. It is the condition that interrupts the flow of code and results in the termination of the program.
In Java, if an exception is encountered while execution of the code, the occurrence is called thrown. Therefore, we say that an exception is thrown by the program.
If not handled, the exceptions can cause termination of the program. Coming back to our example, fortunately, by default, Java handles this exception using ArithmeticException class. Still, we don't want to scare the user with red and blue details, so we will try to handle the exception (if occurred) using try and catch blocks.
Why Do We Need an Exception?
Now, you may think that we can just use an if block and prevent the occurrence of this state. Then why do we need exceptions?
Dividing by zero is an easy example to catch, but there are many complex situations where exceptions are better to implement. An example of a pre-defined exception in Java is IllegalArgumentException. This exception is thrown when an inappropriate argument is passed in a method.
The advantage of exceptions are:
once we define the scope of a particular exception, we will have to define the corresponding catch blocks only once. In the case of if blocks, we will have to use it whereever there is a possibility of the exception occurring.
Exceptions allow us to isolate the details of mistakes in the logic of our code as it is encountered. By categorizing the exceptions, we can be sure that what is wrong with the code.
Exceptions also allows you to control the termination of the program. Instead of throwing an exception and abruptly ending the program, you can decide what to do when a particular exception occurs.
Types Of Exceptions in Java
Let's discuss types of exceptions. There are two types of exceptions in Java, Checked Exceptions and Unchecked Exceptions.
Checked Exceptions are the exceptions that are thrown at the compile time. The programmer cannot ignore these and has to rectify them before running the program. Examples of Checked Exceptions would be ClassNotFoundException, IOException, etc.
Unchecked Exceptions are the exceptions that are thrown at the run time (and therefore, also known as Runtime Exceptions). These can get ignored at the time of compiling. Examples of Unchecked Exceptions would be ArithmeticException, ArrayIndexOutOfBoundsException, NullPointerException Exception, etc.
How to Handle Exceptions?
So after understanding exceptions and the interruptions they can cause, let's understand how to handle them.
We handle the exceptions with the help of Exception Handling. You can use try and catch blocks to handle exceptions. Try block is used to define the scope where an exception can occur. The exception, if caused, is then handled by the catch block. In the next part, we will understand the syntax of Try and Catch blocks.
Try Block in Java
Syntax of Try Block in Java
The try statement allows us to define a block of code that will be checked for exceptions while it runs. Therefore, the try block includes the statements that might throw an exception during execution.
Catch Block in Java
Syntax of Catch in Java
If an exception occurs in the try block, the catch statement allows us to define a block of code that will be executed to handle the exception. Therefore, the catch block is used in couple with the try block. We can use multiple catch statements if we want. This is discussed later in the article.
Example of Try and Catch
As mentioned above, try and catch blocks are used together for exception handling.
- Divide by zero is an ArithmeticException in Java. It is thrown when we try to divide a number by 0.
- You can see that the values of a and b are printed with the messages, however the value of c is not printed.
- This is because the exception is thrown at line number 11. After that it skips the remaining statements in the try block and the control moves to the catch block.
Finally Block in Java
Finally block is used to execute the necessary code after the try and catch block. Finally block is always executed regardless of the result of the try and catch blocks.
Syntax of Finally Block in Java
Example of Finally Block in Java
Let's see both the cases, where an exception occurs, and where it does not occur.
- Example of Finally block with an exception in the try block:
Try and catch blocks are the same as the above examples, but we can see that the code in the finally block is executed.
Even if there is no occurrence of an exception, it will still be executed as shown below.
- Example of Finally Block with no exceptions thrown in the try block:
We can see that there is no exception thrown in the try block, but still the code in the finally block is executed.
In Java, we have some pre-defined exceptions known as Built-in Exceptions which are accessible using libraries. These are common exceptions such as:
User Defined Exceptions
In Java, we can make User Defined Exceptions. User Defined Exceptions are made by extending the Exception class. We have to check for the abnormality, and if in any step we found it, we need to throw the exception using the throw keyword.
Multiple Catch Blocks in Java
We can use multiple catch blocks with a single try block. This helps us to deal with different exceptions differently. Since we are dealing with different exceptions, the parameters of every catch block should be different.
Example of Multiple Catch Blocks:
- We have two catch blocks, and the exception thrown is an instance of both ArithmeticException and Exception classes.
- But the ArithmeticException block is first in the sequence, and hence, it is executed.
- After executing it, the second catch is skipped, because at most one catch block can be executed for one try block.
- If the catch block is executed, and if there is an exception caused in that catch block, then it needs to be handled separately and if not handled, it will stop the execution of the code abruptly throwing an exception. (it will be discussed later in the article)
- No more than one catch block is executed for an exception.
- It is better to order the catch blocks from specific to general exceptions so that the general exception catch block doesn’t cover the specific case in it.
Internal Working of Java Try and Catch Blocks
Whenever a method encounters an Exception, it produces an object known as an Exception object and passes it to the runtime environment. The Exception object has the information about the exception, such as its kind and the program's state at the time of the occurrence. Throwing an exception is the process of creating an exception object and passing it to the runtime environment.
When a method throws an exception, the runtime environment looks for a way to deal with it. If the exception is handled in the program, it runs the rest of the code. If the exception is not handled, the runtime environment prints out the details of the exception then prints the stack history and terminates the program.
Nested Try Catch
In Java, a try-catch block inside another try-catch is allowed, and it is called Nested Try Catch. Every possibility of an exception can be delved with using Nested Try Catch. An example where Nested Try Catch can be used in calculating the average of an array. ArithmeticException and ArrayIndexOutOfBoundsException both need to be handled in this case.
Syntax of a Nested Try Block
Example of a Nested Try Block
- The first exception is caused by the first inner try and catch block, and it is an ArrayIndexOutOfBoundsException. Its message is then printed.
- The second exception is caused by the second inner try and catch block, and it is an ArithmeticException. Its message is then printed.
- The Third exception is handled by the outer try and catch block because it lies in the outer try block. Its message is then printed.
Java Exception Class Hierarchy
Exception hierarchy is followed by the nested catch blocks. When we have nested catch blocks, as soon as a catch matches the exception thrown, it executes the code inside it and then other catch blocks are ignored by the execution. The finally block (if present) is then executed and the execution continues.
- In Java, all exception classes extend the class Throwable. The Error and Exception are the two subclasses of Throwable class.
- The exceptions or abnormalities that our code is not supposed to encounter in ideal conditions, is defined in the Error class. Examples of some errors are JVM errors, Memory errors, etc.
- The exceptions or abnormalities in our code that can be managed by either the compiler itself or if the expectations are handled by the programmer are defined in the Exception class. The try and catch blocks are used to handle these exceptions.
- The exception class has a sub class called the Runtime exception. The runtime exceptions, as the name suggests, describe the exceptions that happen at the runtime and those which can not be thrown at the compile time. Examples of runtime exceptions are NullPointerException, ArrayIndexOutOfBoundsException, etc.
- Then there are Input-Output exceptions also known as IOException, which are thrown in the execution of input-output operations.
- In Java, interrupted exceptions are thrown when many threads are active and synchronization is not available.
Java try-with-resources Statement
In many situations, we want that some part of our code should be executed regardless of whether some exceptions occurred or not. For example: if we open a file in the try, no matter if an exception occurs or not, we have to close it. Here, try-with-resources comes in handy.
Now it is very easy for us to think of try-with-resources as a replacement to finally block. If we try to replicate the try-with-resources statement with a try, catch and finally block, we can run into a problem. The problem is that what if the exception for which we are using try, catch can also be occurred in the finally block, even if we use a nested try-catch block, it is difficult to replicate the try-with-resources statement.
The try-with-resources statement was added to Java 7. By using the try-with-resources statement, we can ensure that all the objects that need to be closed are closed automatically, and exceptions regarding those objects are delved by-catch of this try only.
Q. What happens if a catch block throws an exception?
A. If the catch block throws an exception, and it is not handled by the nested try and catch block within the catch block where the exception is thrown, then it will cause the termination of the program.
Q. What is Try, Catch, and Finally in Java?
A. The try-catch-finally is the flow control statement in Java. They help us to handle exceptions in the program.
Q. Can finally block have a try and catch block?
A. Yes, we can use a try-catch block inside of a finally block.
Q. Throws vs Throw in try and catch Java?
A. We use the “throws” keyword to declare the exception with the method declaration. And “throw” is used to forcibly throw the exception, while the try-catch blocks is used to handle the exceptions thrown by the code.
Q. What are the types of Exceptions and their hierarchy?
A. Types of Exceptions and their hierarchy are pictorially represented in this diagram:
- We use Exception Handling to prevent abnormal situations, which may cause the termination of that program. We also use it to log and maintain the flow of our program.
- The code which may throw an exception is enclosed in the try block, and the catch block helps to address the exceptions if they occur.
- Finally block is always executed, unless there is some unhandled exception that terminates the program.
- We can use the predefined exceptions for handling abnormal situations or even define and throw new exceptions with the help of the throws keyword.
- Exceptions caused in a catch block should be handled separately.