To begin, let’s look at a real-world example of exception handling.
We’re walking down the street when someone throws a ball at us. What will you do?
Similarly, in any application, small or large, unexpected scenarios are bound to occur, and exceptions are generated by the runtime environment to indicate this. An exception in Java is an event that disrupts the normal flow of the program. It is an object that the JVM throws at runtime whenever such a situation arises. In large applications, the number of factors that can go wrong increases dramatically, such as network issues, infrastructure issues, database issues, coding issues, power issues, and mistakes.
Exception Handling is simply the concept of dealing with unexpected failures in the most efficient and desirable way possible so that the system does not crash, resulting in a poor user experience.
As in above example Exception can be handled in three ways :-
If an exception is not caught, the virtual machine will stop executing the program and display an appropriate message to the console. In this section, we’ll go over some of the most common exception types in Java, as well as the syntax for throwing and catching exceptions within user-defined code blocks.
If an exception occurs and is not handled, the Java runtime system will terminate the program after printing an appropriate message and a runtime stack trace.
Before going in-depth with exception handling let us consider the following scenario.
1. Assume you own an airline company. There may now be some rules and regulations that apply to all airlines. For example, having a pilot and crew on board is almost always required. If you break this rule, you will not be able to fly. This is a compile-time error. When you violate code rules, the compiler refuses to compile the code.
2. In the event of an emergency, airlines must have safety measures in place on their planes. The air hostess's safety speech is the airline's way of saying, "Hey, things could go wrong". That’s declaring an "Exception". This is accomplished by including "throws" in the declaration of a risky method in Java.
3. Life jackets are placed beneath each seat on all airline planes to protect passengers in the event that the plane crashes into the sea. That life jacket is handled exceptionally well. You accomplish this by enclosing the risky code in try and catch blocks.
4. What if the plane crashes above land rather than at sea? There are no parachutes available. You're avoiding the exception. When no one handles an exception, including main(), the JVM simply terminates the program with the exception. (A plane crash kills people.)
5. In general, planes crash due to engine failure or pilot error. The pilot may attempt a safe landing. These are runtime errors. You can try to deal with them. However, the compiler is unconcerned if you do not declare or handle runtime exceptions. All other exceptions are checked exceptions that must be declared or the compiler will throw a compile time error.
6. Assume two planes are flying from point A to point B. Plane 1 crashed into the sea (exception), but passengers were able to survive by wearing life jackets (catch). Finally, you must transport both plane 1 and 2 passengers to their destination B. This is where it all comes together. In a finally block, you put the code that should run regardless of whether there is an exception or not.
Keep these scenarios on the back of your head for now. Do not worry if you do not understand all the buzzwords. They will be clear to you in a few minutes. You can learn more about Exception Handling from wikipedia.
What Is An Exception?
The term exception is shorthand for the phrase “exceptional event”.
Definition: An exception is an event, which occurs during the execution of a program, that disrupts the normal flow of the program's instructions.
When a method encounters an error, the method creates an object and passes it to the runtime system. The object, known as an exception object, contains information about the error, such as its type and the program’s state at the time the error occurred. Throwing an exception is the act of creating an exception object and passing it to the runtime system.
When a method throws an exception, the runtime system looks for a way to handle it. The ordered list of methods that were called to get to the method where the error occurred is the set of possible “somethings” to handle the exception. The call stack is the list of methods (see the next figure).
The runtime system searches the call stack for a method that contains a block of code that can handle the exception. This section of code is known as an exception handler. The search starts with the method where the error occurred and works its way up the call stack in the reverse order in which the methods were called. When an appropriate handler is found, the exception is passed to the handler by the runtime system. If the type of the exception object thrown matches the type that the handler can handle, an exception handler is considered appropriate.
The chosen exception handler is said to catch the exception. If the runtime system searches all the methods on the call stack and does not find an appropriate exception handler, as shown in the following figure, the runtime system (and thus the program) terminates.
The Catch or Specify Requirement
The Catch or Specify Requirement must be honored by valid Java programming language code. This means that any code that may throw an exception must be surrounded by one of the following:
A try statement that handles exceptions. The try must provide an exception handler, as described in Catching and Handling Exceptions.
A method that specifies that it has the ability to throw an exception. As described in Specifying the Exceptions Thrown by a Method, the method must include a throws clause that lists the exception.
Code that does not meet the Catch or Specify Requirement will fail to compile.
The Catch or Specify Requirement does not apply to all exceptions. To understand why, consider the three basic types of exceptions, of which only one is subject to the requirement.
The Three Kinds of Exceptions
The checked exception is the first type of exception. These are unusual circumstances that a well-written application should be able to anticipate and recover from. Assume an application prompts a user for an input file name, then opens the file by passing the name to the constructor for java.io.FileReader. Normally, the user provides the name of an existing, readable file, allowing the FileReader object to be constructed and the application to run normally. However, if the user enters the name of a nonexistent file, the constructor throws a java.io.FileNotFoundException. A well-written program will catch this exception and alert the user to the error, possibly prompting a new file name.
The Catch or Specify Requirement applies to checked exceptions. Except for Error, RuntimeException, and their subclasses, all exceptions are checked exceptions.
The error is the second type of exception. These are exceptional conditions that occur outside of the application and that the application cannot normally anticipate or recover from. Assume an application successfully opens a file for input but is unable to read the file due to a hardware or system failure. The failed read will result in a java.io.IOError. An application may choose to catch this exception in order to notify the user of the issue, but it may also be appropriate for the program to print a stack trace and exit.
The Catch or Specify Requirement does not apply to errors. Errors are exceptions that are indicated by Error and its subclasses.
The runtime exception is the third type of exception. These are exceptional conditions that exist within the application and that the application cannot normally anticipate or recover from. These typically indicate programming errors, such as logic errors or improper API usage. Consider the previously described application, which passes a file name to the FileReader constructor. If a null is passed to the constructor due to a logical error, the constructor will throw NullPointerException. The application can handle this exception, but it’s probably better to fix the bug that caused it in the first place.
The Catch or Specify Requirement does not apply to runtime exceptions. Runtime exceptions are those that are identified by RuntimeException and its subclasses.
Errors and runtime exceptions are collectively known as unchecked exceptions.
How To Catch And Handle Exceptions?
This section describes how to write an exception handler using the three exception handler components — the try, catch, and finally blocks.
The following example defines and implements the ListOfNumbers class. ListOfNumbers construct an ArrayList with 10 Integer elements with sequential values 0 through 9. The ListOfNumbers class also includes a writeList method that saves the list of numbers to a text file called OutFile.txt. This example employs java.io output classes, which will be covered in a later tutorial.
import java.io.*;
import java.util.List;
import java.util.ArrayList;
public class ListOfNumbers {
private List<Integer> list;
private static final int SIZE = 10;
public ListOfNumbers () {
list = new ArrayList<Integer>(SIZE);
for (int i = 0; i < SIZE; i++) {
list.add(i);
}
}
public void writeList() {
// The FileWriter constructor throws an IOException, which must be caught.
PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));
for (int i = 0; i < SIZE; i++) {
// The get(int) method throws IndexOutOfBoundsException, which must be caught.
out.println("Value at: " + i + " = " + list.get(i));
}
out.close();
}
}
The code will not compile. The compiler says there’s an “unreported exception” that must be caught or declared.
ListOfNumbers.java:19: error: unreported exception IOException; must be caught or declared to be thrown
PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));
^
1 error
What happens when a method you want to call is risky (likely in a class you didn’t create)?
Exceptions are used by Java methods to notify the calling code that “Something Bad Happened.” “I messed up.”
The exception-handling mechanism in Java is a clean, well-lighted way to handle “exceptional situations” that arise during runtime; it allows you to put all your error-handling code in one easy-to-read location. It is predicated on your understanding that the method you are calling is risky (i.e. that the method may throw an exception), so that you can write code to deal with that possibility. If you know you may get an exception when calling a specific method, you can prepare for—and possibly recover from—the problem that caused the exception.
So, how do you determine whether a method throws an exception? A throws clause can be found in the declaration of the risky method.
The constructor FileWriter(String fileName) takes a risk. It may fail during runtime. As a result, when you call it, it must “declare” the risk you are taking.
How To Use The try Block?
The compiler needs to know that YOU know you’re calling a risky method.
The compiler will relax if you wrap the risky code in a try/catch block.
A try/catch block informs the compiler that you are aware that an exceptional event may occur in the method you are calling and that you are prepared to handle it. The compiler doesn’t care how you handle it; it only cares that you say you’re handling it.
The first step in constructing an exception handler is to enclose the code that might throw an exception within a try block. In general, a try block looks like the following:
try {
code...
}
catch and finally blocks . . .
The code segment in the example contains one or more legal lines of code that may throw an exception. (The catch and finally blocks are covered in the following two sections).
Enclose the exception-throwing statements of the writeList method within a try block to create an exception handler for the ListOfNumbers class’s writeList method. There are several approaches to this. Each line of code that may throw an exception can be contained within its own try block, with its own exception handler. Alternatively, you can put all of the writeList code in a single try block and associate it with multiple handlers. Because the code in question is so short, the following listing only uses one try block for the entire method.
private List<Integer> list;
private static final int SIZE = 10;
public void writeList() {
PrintWriter out = null;
try {
System.out.println("Entered try statement");
FileWriter f = new FileWriter("OutFile.txt");
out = new PrintWriter(f);
for (int i = 0; i < SIZE; i++) {
out.println("Value at: " + i + " = " + list.get(i));
}
}
catch and finally blocks . . .
}
If an exception occurs within the try block, it is handled by the exception handler that is associated with it. To connect an exception handler to a try block, add a catch block after it; the next section, The catch Blocks, explains how.
How To Use The Catch Block?
Exception handlers are associated with a try block by following it with one or more catch blocks. There can be no code between the end of the try block and the start of the first catch block.
try {
} catch (ExceptionType name) {
} catch (ExceptionType name) {
}
Each catch block is an exception handler that handles the type of exception specified by its argument. The argument type, ExceptionType, declares the type of exception that the handler can handle and must be the name of a class that inherits from the Throwable class. The handler can refer to the exception by name.
The catch block contains code that is executed if and when the exception handler is called. When the exception handler is the first one in the call stack whose ExceptionType matches the type of the exception thrown, the runtime system calls it. The system considers it a match if the thrown object can legally be assigned to the exception handler’s argument.
The following are two exception handlers for the writeList method:
try {
} catch (IndexOutOfBoundsException e) {
System.err.println("IndexOutOfBoundsException: " + e.getMessage());
} catch (IOException e) {
System.err.println("Caught IOException: " + e.getMessage());
}
Exception handlers are capable of doing more than just printing error messages or terminating the program. They can use chained exceptions to perform error recovery, prompt the user for a decision, or propagate the error up to a higher-level handler, as described in the Chained Exceptions section.
What Is The finally Block?
When you need to execute important code after an exception, put it inside the finally block. For example, in the try block, you open a file, but due to some reason in try block, an exception occurs, and control is transferred directly to the catch block. Then, if you have written a finally block, you close that file inside the finally block. That is, if we want to execute some code after an exception, we should put it inside a finally block, according to Java.
Similarly, if you are connected to a database and an exception occurs for some reason, it is your responsibility to close the connection with the database, so the connection closing code should be written inside the finally block.
When the try block terminates, the finally block always executes. This ensures that even if an unexpected exception occurs, the finally block is executed. Finally, it is useful for more than just exception handling because it prevents cleanup code from being accidentally bypassed by a return, continue, or break. Even when no exceptions are expected, putting cleanup code in a finally block is always a good practice.
Note: The finally block may not execute if the JVM exits while the try or catch code is being executed.
The try block of the writeList method you’ve been working on opens a PrintWriter. Before exiting the writeList method, the program should close that stream. This presents a somewhat complicated problem because the try block of writeList can exit in one of three ways.
The new FileWriter statement fails and throws an IOException.
The list.get(i) statement fails and throws an IndexOutOfBoundsException.
Everything succeeds and the try block exits normally.
Regardless of what happens in the try block, the runtime system always executes the statements in the finally block. As a result, it’s an ideal location for cleaning.
The following finally block for the writeList method cleans up and then closes the PrintWriter and FileWriter.
finally {
if (out != null) {
System.out.println("Closing PrintWriter");
out.close();
} else {
System.out.println("PrintWriter not open");
}
if (f != null) {
System.out.println("Closing FileWriter");
f.close();
}
}