An exception is an event that occurs during the execution of a program and disrupts the normal (expected) flow of the program. In programming, the word “exception” refers to an “exceptional event.”
Suppose we’ve written a method that throws an exception on executing. As soon as the exception is thrown, the runtime system attempts to find an exception handler. The system searched those methods that had been called to get to the method with the exception. This list of methods is often termed a call stack.
The search proceeds in top-down order in the call stack to find the suitable exception handler. That is, first the method with the exception is searched, then the method which called this method, and so on….
Search is done from top to bottom
Note: An exception handler is considered suitable if the thrown exception’s type matches the type that the handler can handle. In case the system doesn’t find a suitable handler, the program terminates.
A good java method must ensure at least one of the following:
Exceptions are depicted by certain classes in Java. The java.lang.Throwable is the root class in Java Exceptions, which has two children Exception and Error.
Checked Exceptions: These are the most anticipated exceptions and are recoverable also. All classes except RuntimeException and Error class families have checked exceptions.
A trivial example is regarding File handling. The user gives the name of a file to read, if it exists, then there’s no harm; otherwise, the method will throw java.io.FileNotFoundException.
import java.io.FileReader;
class CheckedException{
public static void main (String[] args) {
//reading file "name.txt"
FileReader file= new FileReader("name.txt");
//The bold part may throw an exception if file does
// not exist or for some other I/O reason.
}
}
Unchecked exceptions: Error and Runtime exception.
Now let’s first see how to catch and handle (writing exception handler) the exceptions, followed by how to specify the exceptions thrown by a method.
Consider the example of a class named FileHandle:
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class FileHandle {
private int divisor;
private String fileName;
private File file;
public FileHandle(int divisor, String fileName) {
this.divisor = divisor;
this.fileName = fileName;
file = new File(fileName);
}
public void writeFile(String input, int dividend) {
//creation of new file using createNewFile
file.createNewFile();
//writing into file
FileWriter abc = new FileWriter(fileName);
abc.write(input);
abc.write(Integer.toString(dividend/divisor));
abc.close();
}
public static void main(String[] args) throws IOException {
//giving a wrong path
String path = "tmp"+File.separator+"HIJAVA.txt";
FileHandle object = new FileHandle(2,path);
object.writeFile("123556",2);
}
}
The FileHandle() constructor takes an integer as a divisor and a string as the path where the file will be created. The writeFile() method takes string and integer as arguments, creates the required file with createNewFile(), and writes in it using FileWriter class.
The first line in boldface may throw an IOException if the file is not created properly. Similarly, the FileWriter constructor may also throw the same exception. If the file is successfully created, the third line in boldface may throw an Arithematic exception in case the divisor is 0.
Output message with the wrong path:
Exception in thread "main" java.io.IOException: The system cannot find the path specified
at java.io.WinNTFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:1023)
at FileHandle.writeFile(FileHandle.java:16)
at FileHandle.main(FileHandle.java:28)
Notice that only the exception thrown by the createNewFile() method is displayed and the arithmetic error is not shown. This is because createNewFile() throws IOException error which is a checked exception, whereas ArithematicException is an unchecked exception.
It is the first component of any exception handler. Syntax :
try {
//code
}
catch and finally blocks...
The code block contains the code that may throw exception(s). We’ll leave catch and finally blocks for later.
To make an exception handler for the writeFile() method, we will enclose the exception-throwing statements in the try
block. We can either enclose all statements in one block or treat each statement individually. Here’s the code:
FileWriter abc = null;
try{
file.createNewFile();
//writing into file
abc = new FileWriter(fileName);
abc.write(input);
abc.write(Integer.toString(dividend/divisor));
abc.close();
}
catch and finally ...
If an exception occurs inside the try block, it is handled by the exception handler that is connected with it. The catch block associated with the try block handles the exception.
The catch block should come directly after the try block. No code can be between the end of the try
block and the beginning of the first catch
block. There can be more than one catch
associated with a single try
block.
Syntax:
try {
//code which may throw exceptions
} catch (ExceptionType varname){
//code to handle exception
} catch (ExceptionType varname){
//code to handle exception
}
Each catch block handles the type of exception indicated by its argument. That is, ExceptionType should be a valid class that inherits the Throwable class. As soon as the code in the try block throws an exception, the runtime system searches for an appropriate catch block compatible with thrown exception (the ExceptionType matches).
For our writeFile() we write the following catch blocks:
try{
//same as previous
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (ArithmeticException e) {
System.err.println(e.getMessage());
}
The finally block is executed after completion of the try-catch block irrespective of the facts whether an exception is thrown or an exception is thrown but not handled or the thrown exception is handled. But, it will not be executed if the JVM exits while executing the try-catch block or if some fatal error occurs and the program is aborted.
In our example, we should close the FileWriter and file object.
finally{
if(file!=null){
System.out.println("closing file");
}
else{
System.out.println("file not open");
}
if(abc!=null){
System.out.println("closing abc");
}
else{
System.out.println("abc not open");
}
}
Now, the writeFile() method will be:
public void writeFile(String input, int dividend){
//creation of new file using createNewFile
FileWriter abc=null;
try{
file.createNewFile();
//writing into file
abc = new FileWriter(fileName);
abc.write(input);
abc.write(Integer.toString(dividend/divisor));
}catch (IOException e) {
System.err.println(e.getMessage());
} catch (ArithmeticException e) {
System.err.println(e.getMessage());
}finally{
if(file!=null){
System.out.println("closing file");
}
else{
System.out.println("file not open");
}
if(abc!=null){
System.out.println("closing abc");
}
else{
System.out.println("abc not open");
}
}
}
We made an exception handler for writeFile() in the method itself. But we can allow a method further up in the call stack to handle the exception thrown by the writeFile() method. Thus we state that:
If the writeFile() method doesn’t catch the checked exception that can occur within it, then it must specify the exceptions it can throw.
Generally, it is a good practice to specify the exceptions which can be thrown by the method even if we provide a handler in it. This can be done using the keyword throws with the writeFile() method.
Syntax:
public void writeFile(String input, int dividend) throws ExceptionType1, ExceptionType2... {
//method body
}
The boldfaced part is called the throws clause of the method. ExceptionType1, ExceptionType2…, and so on are the possible exceptions thrown by the method.
NOTE: Unchecked exceptions are not mandatory in the throws clause.
Thus we can write:
public void writeList(String input, int dividend) throws IOException {
}
or
public void writeList(String input, int dividend) throws IOException, ArithmeticException {
}
We are able to handle and catch exceptions because they are being thrown by some other part of the program or system. Throwing exceptions can be done manually by the throw statement. It requires a throwable object as an argument. Throwable objects are objects of any subclass of the Throwable class. Syntax:
throw object;
//throw is a keyword
Example:
public void checkDivideByZero(int divisor) {
if(divisor==0) {
throw new ArithmeticException("Divide By Zero error.");
}
}
NOTE: throw and throws are two different keywords and are completely different. The throws clause is used to specify the exceptions that a method may throw. Whereas, the throw statement actually throws the exceptions.
Enjoy learning, Enjoy oops!