This chapter is taken from the book - Getting started with Java programming language (https://www.amazon.com/dp/1544614519/). You can download the code for the book from here: https://drive.google.com/file/d/0B1IwsLB5TOglZXYxWW9JMndUX3M/view

Chapter 8 - Exception Handling

8-1 Introduction

We saw in chapter 6 that an exception represents a problem with the program that results in immediate termination of the program. In this chapter, we’ll look at:
 exceptions that you’ll normally come across while writing Java programs
>  checked and unchecked exceptions
>  how to create custom exceptions
>  how to catch exceptions and handle them gracefully
Let’s look at what are exception classes and how they are used in programs.

8-2 Exception classes

In Java, an exception is represented by a class. Java defines built-in exception classes representing common exception conditions. For instance, java.lang.NullPointerException represents an exception condition that occurs when you access attributes and methods of a reference type variable set to null.

When an exception occurs during program execution, following things happen:
>  the program execution is halted
>  an appropriate exception object representing the exception condition is created (also referred to as thrown), and
 the newly created exception object is returned to the calling method

All exception classes in Java directly or indirectly inherit from java.lang.Throwable class. The following figure shows some of the important direct and indirect subclasses of Throwable class:
Figure 8-1 The direct and indirect subclasses of Throwable class

The above figure shows that java.lang.Error and java.lang.Exception are subclasses of Throwable. The Error and its subclasses represent unrecoverable exceptions; that is, exceptions that a program can’t recover from. For instance, an object of java.lang.OutOfMemoryError class (a subclass of Error) is thrown if JVM cannot create an object in the heap memory area because there is no memory space left in the heap memory area. A program can’t recover from java.lang.OutOfMemoryError exception.

The Exception and its subclasses represent exceptions that a program can recover from. For instance, an object of java.lang.NullPointerException class (a subclass of Exception) is thrown when a method is called on a reference type variable set to null. A program can recover from java.lang.NullPointerException.

Exception’s subclasses are divided into two categories:
>  checked exception classes – a checked exception must be handled in the program. Excluding java.lang.RuntimeException, the remaining subclasses of Exception class represent checked exceptions. For instance, java.lang.ClassNotFoundException is an example of checked exception.
>  unchecked exception classes – an unchecked exception is not required to be handled in the program. An unchecked exception is represented by java.lang.RuntimeException and its subclasses. For instance, java.lang.NullPointerException is an example of unchecked exception.

NOTE You can create new checked and unchecked exceptions by subclassing Exception and RuntimeException classes, respectively.

Let’s look at some common exceptions that are thrown by Java programs.

IMPORT It is recommended that you import the exceptions project into your Eclipse IDE.

java.lang.NullPointerException

The following listing shows the NullReference class whose main method calls area method of Rectangle object:

Listing 8-1 NullReference class – throws NullPointerException
Project: exceptions
Source location: src\com\sample\NullReference.java
1     package com.sample;
2
3     public class NullReference {
4         private static Rectangle rectangle;
5        
6         public static void main(String args[]) {
7             int area = rectangle.area();          java.lang.NullPointerException
8             System.out.println("Area: " + area);   not executed
9         }
10     }
On line #4, rectangle static variable of type Rectangle is defined. And, on line #7, Rectangle object’s area method is called. If you run NullReference’s main method, you’ll get the following output:
Exception in thread "main" java.lang.NullPointerException
    at com.sample.NullReference.main(NullReference.java:7)
The output shows that an exception occurred on line #7 of NullReference class, and the exception is java.lang.NullPointerException. As "Area: " was not shown in the output, it means the statement System.out.println("Area: " + area) of NullReference class (refer line #8) was not executed.
A NullPointerException is thrown when you call methods or access attributes using a reference type variable that is set to null. As we didn’t create and assign a Rectangle object to the rectangle variable, the rectangle variable was set to null at the time area method was called on line #7.
Let’s now modify the NullReference class’s main method such that it doesn’t throw NullPointerException when the rectangle variable is set to null.
Hands-on Modify NullReference’s main method to avoid NullPointerException
To avoid NullPointerException, check if the reference type variable is set to null or not before calling any methods or accessing any attributes.
The following listing shows the modified NullReference class whose main method calls area method only if the rectangle variable is not set to null:
Listing 8-2 NullReference class – doesn’t throw NullPointerException
1     package com.sample;
2
3     public class NullReference {
4         private static Rectangle rectangle;
5        
6         public static void main(String args[]) {
7              if(rectangle == null) {
8                    System.out.println("rectangle variable doesn’t refer to a Rectangle object");   
9               } else {
10                   int area = rectangle.area();         
11                   System.out.println("Area: " + area);                 
12               }
13         }
14     }
On line #7, we check if the rectangle variable is set to null. As rectangle variable is set to null, the statements on line #10 and #11 are not executed. So, if you now run the main method of NullReference class, you’ll get the following output:
rectangle variable doesn’t refer to a Rectangle object

java.lang.ClassCastException

The following listing shows WrongCasting class whose main method performs upcasting and downcasting of objects:
Listing 8-3 WrongCasting class – throws ClassCastException
Project: exceptions
Source location: src\com\sample\WrongCasting.java
1     package com.sample;
2
3     public class WrongCasting {
4         public static void main(String args[]) {
5             Object rectangle = new Rectangle(10, 10);
6             String str = (String) rectangle; throws java.lang.ClassCastException
7             System.out.println("String str : " + str);        not executed
8         }
9     }
On line #5, an object of Rectangle class is created and assigned to Object type variable. On line #6, rectangle variable that holds reference to the Rectangle object is assigned to a String type variable. If you run WrongCasting’s main method, you’ll get the following output:
Exception in thread "main" java.lang.ClassCastException: com.sample.Rectangle cannot be cast to java.lang.String
    at com.sample.WrongCasting.main(WrongCasting.java:6)
The output shows that an exception occurred on line #6 of WrongCasting class, and the exception is java.lang.ClassCastException. As "String str: " was not printed, this means that statement System.out.println("String str: " + str) of WrongCasting class (refer line #7) was not executed. Notice that the cause of exception is also printed: "com.sample.Rectangle cannot be cast to java.lang.String".
A ClassCastException is not thrown if you cast an object to a type which is either of the same type as the object or it is supertype of the object. In all other cases, a ClassCastException is thrown. As String is not a supertype of Rectangle, the assignment fails on line #6 and ClassCastException is thrown.
NOTE As explained in section 7-4 of chapter 7, you can use the instanceof operator to check the runtime type of an object before performing downcasting or upcasting of the object. This means, you can use the instanceof operator to avoid java.lang.ClassCastException.

java.lang.ArithmeticException

The following listing shows DivisionByZero class whose main method divides an integer number by 0:
Listing 8-4 DivisionByZero class – throws ArithmeticException
Project: exceptions
Source location: src\com\sample\DivisionByZero.java
1     package com.sample;
2
3     public class DivisionByZero {
4         public static void main(String args[]) {
5             int i = 1/0;  throws java.lang.ArithmeticException
6             System.out.println("Value of i is " + i);not executed
7         }
8     }
On line #5, integer 1 is divided by 0 and the result is assigned to i. If you run DivisionByZero’s main method, you’ll get the following output:
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.sample.DivisionByZero.main(DivisionByZero.java:5)
The output shows that an exception occurred on line #5 of DivisionByZero class, and the exception is java.lang.ArithmeticException. As "Value of i is " was not printed, this means that statement System.out.println("Value of i is " + i) of DivisionByZero class (line #6) was not executed. Notice that the cause of exception is also printed as " / by zero ".
Now that we’ve seen some of the built-in exception types in Java, let’s look at what happens when an exception is thrown by a method.

8-3 Exception propagation and handling

In Java applications, a method typically calls one or more methods of other objects in the application. When an exception occurs, an exception object is returned to the calling method. A method is said to handle an exception, if it catches the exception and stops it from propagating to the calling method.
Let’s say that the main method (which acts as the entry point into a Java application) calls method x of object X, and method x calls method y of objecY, and method y calls method z of object Z.


Figure 8-2 An example method call chain
If an exception occurs in method z, the exception is returned to method y if method z can’t handle it. If method y can’t handle the exception, it is returned to method x. If method x can’t handle the exception, it is returned to the main method. If the main method can’t handle the exception, it is handled by the JVM. The JVM catches the exception and writes the exception details (which include exception type, object which caused the exception, and the line number on which the exception occurred) to the output.
Let’s look at an example that shows how unhandled exceptions propagate to the calling method.
The following figure shows objects and methods that are responsible for performing fund transfer in a banking application:
Figure 8-3 A banking application’s objects and their methods

In the above figure, FundTransfer class defines transferFunds method that transfers money from one account to another, and Account class represents a bank account that defines credit and debit methods. The steps followed for transferring funds from account xAcc to account yAcc are:
>  InternetBanking’s main method calls FundTransfer’s transferFunds method (represented by line labelled ) to transfer amt amount from xAcc to yAcc account. xAcc and yAcc are Account objects representing the bank accounts involved in the fund transfer.
>  FundTransfer’s transferFunds method calls xAcc’s debit method (represented by line labelled ) to debit the amt amount from it, and calls yAcc’s credit method (represented by line labelled ) to credit amt amount to it.

IMPORT It is recommended that you import the exception-propagation project into your Eclipse IDE.

The following listing shows the FundTransfer class:
Listing 8-5 FundTransfer class
Project: exception-propagation
Source location: src\com\sample\FundTransfer.java
1     package com.sample;
2
3     public class FundTransfer {
4         public static boolean transferFunds(Account xAcc, Account yAcc, int amt) {
5             xAcc.debit(amt);
6             yAcc.credit(amt);
7             System.out.println("Completed fund transfer");
8             return true;
9         }
10     }
The transferFunds method is a static method that debits amt amount from xAcc account and credits amt amount to yAcc account. After successful transfer, the method prints the message "Completed fund transfer" and returns true in the end.
The following listing shows the Account class that represents a bank account:

Listing 8-6 Account class
Project: exception-propagation
Source location: src\com\sample\Account.java
1     package com.sample;
2
3     public class Account {
4         private int accountNumber;
5         private int currentBalance;
6         .....
7         public void credit(int amt) {
8             currentBalance = currentBalance + amt;
9         }
10
11        public void debit(int amt) {
12            int tempBalance = currentBalance - amt;
13            if (tempBalance < 0) {
14                int i = 1 / 0; throws java.lang.ArithmeticException
15                System.out.println(i); never executed
16            }
17            currentBalance = tempBalance;
18        }
19        .....
20    }
The accountNumber and currentBalance instance variables represent the unique bank account number and the current account balance, respectively. The credit method (line #7) adds the given amt amount to currentBalance. The debit method (line #11) needs to meet the following requirements:
>  As the bank account can’t have negative balance, the debit method subtracts amt amount (the amount to be debited) from currentBalance only if it doesn’t lead to negative balance. For this reason, tempBalance variable is defined on line #12 to temporarily hold account balance after subtracting amt from currentBalance. If tempBalance < 0 condition evaluates to false on line #13, the tempBalance value is assigned to currentBalance on line #17.
 If debiting amt amount can lead to negative balance, the execution of debit method must stop. To achieve this requirement, if tempBalance < 0 (refer line #13) condition evaluates to true, we divide 1 by 0 (refer line #14). We saw earlier that division by 0 results in java.lang.ArithmeticException (refer listing 8-4). This means, if tempBalance < 0 evaluates to true, ArithmeticException will be thrown on line #14 and the execution of debit method will stop. This also means that the statement System.out.println(i) on line #15 will never be executed.
The following listing shows InternetBanking class whose main method calls FundTransfer’s transferFunds method:

Listing 8-7 InternetBanking class
Project: exception-propagation
Source location: src\com\sample\InternetBanking.java
1     package com.sample;
2
3     public class InternetBanking {
4         public static void main(String args[]) {
5             Account xAcc = new Account(1, 1000);
6             Account yAcc = new Account(2, 1200);
7            
8             FundTransfer.transferFunds(xAcc, yAcc, 1400);
9             System.out.println("xAcc’s current balance " + xAcc.getCurrentBalance());
10            System.out.println("yAcc’s current balance " + yAcc.getCurrentBalance());
11            System.out.println("Completed execution of main method");
12         }
13    }
At first, main method creates two bank accounts xAcc and yAcc with current balances as 1000 and 1200, respectively. It then calls FundTransfer’s transferFunds method (line #8) to transfer 1400 from xAcc account to yAcc account. If you run InternetBanking’s main method, you’ll get the following output:
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at com.sample.Account.debit(Account.java:19)
    at com.sample.FundTransfer.transferFunds(FundTransfer.java:6)
    at com.sample.InternetBanking.main(InternetBanking.java:8)
NOTE The above output is referred to as exception stack trace. An exception stack trace provides details of methods (and their classes) that were being executed when the exception occurred.
As xAcc account’s balance is 1000 and we are trying to transfer 1400, call to xAcc’s debit method throws ArithmeticException (refer line #14 in listing 8-6). The output shows:
>  Account object’s debit method throws ArithmeticException. As the debit method doesn’t handle the exception, it is returned to the calling transferFunds method.
>  As FundTransfer’s transferFunds method doesn’t handle the ArithmeticException, it is returned to the calling main method.
>  As InternetBanking’s main method doesn’t handle the ArithmeticException, it is handled by the JVM. The above output is written by the JVM, which includes the exception thrown and the methods that were in the call chain when the exception occurred.
Notice that "xAcc’s current balance", "yAcc’s current balance", "Completed execution of main method" (refer InternetBanking class in listing 8-7) and "Completed fund transfer" (refer FundTransfer class in listing 8-5) messages are not printed on the output. This is because the ArithmeticException thrown by debit method not only stops execution of the debit method but also stops execution of calling methods (that is, transferFunds and main methods).

Figure 8-4 shows how the executions of main, transferFunds and debit methods are effected when ArithmeticException occurs. The figure uses numbered balls to represent flow of program control. At , InternetBanking’s main method calls FundTransfer’s transferFunds method. At , FundTransfer’s transferFunds method calls Account’s debit method. At , ArithmeticException is thrown by the debit method which results in transfer of control back to the statement of transferFunds method that called the debit method. As transferFunds method can’t handle the ArithmeticException, control is returned to the statement of main method that called the transferFunds method (refer ). As the main method can’t handle the ArithmeticException, the control is returned to the JVM for handling the exception (refer ).
Figure 8-4 Flow of program control when ArithmeticException is thrown by Account’s debit method

The greyed-out statements shown in the above figure are not executed because the exception stops execution of debit, transferFunds and main methods.

Let’s now look at how to catch the ArithmeticException thrown by Account’s debit method.

Catching exceptions

To catch exceptions, you need to do the following:
>  enclose statements that may throw an exception in a try statement block
>  immediately following the try statement block, specify one or more catch statement blocks that contain statements to be executed when an exception occurs

The following is the syntax for specifying try-catch block:
1     try {
2         <statement-1>;
3         <statement-2>;
4         .....
5     }
6     catch(<exception-type> <name>) {
a)         <catch-statement1>;
b)         .....
9     }
10    catch(<exception-type> <name>) {
11         <catch-statement2>;
12        .....
13    }
The try block encloses the statements that may throw an exception during execution. The catch statement blocks are executed only when an exception is thrown by a statement in the try block. The <exception-type> specifies the exception type (like, NullPointerException and ClassCastException) for which the catch block is executed, and <name> specifies the name with which the exception object is available in the catch block. The statements contained in the catch block specify how the exception is handled.
Let’s add try-catch block to Account’s debit method (refer listing 8-6) to handle ArithmeticException.
Hands-on Add try-catch block
As shown in the following listing, add try-catch block to the Account class of exception-propagation project:
Listing 8-8 Account class – try-catch block for catching ArithmeticException
1     package com.sample;
2
3     public class Account {
4         .....
5         public void debit(int amt) {
6             try {
7                 int tempBalance = currentBalance - amt;
8                 if (tempBalance < 0) {
9                     int i = 1 / 0; throws java.lang.ArithmeticException
10                    System.out.println(i);
11                }
12               currentBalance = tempBalance;
13            } catch (ArithmeticException ae) { catches ArithmeticException
14                System.out.println(ae); calls toString method of ArithmeticException object
15            }
16        }
17        .....
18    }
In the above listing, try block encloses statements that debit amt amount from currentBalance. If tempBalance < 0 evaluates to true (line #8), ArithmeticException is thrown on line #9. The catch block (line #13) specifies that it is executed when ArithmeticException is thrown by any of the statements in the try block. The catch block contains a single statement that prints the string returned by calling the toString method of the ArithmeticException object.
If you now run InternetBanking’s main method, you’ll get the following output:
java.lang.ArithmeticException: / by zero
Completed fund transfer
xAcc’s current balance 1000
yAcc’s current balance 2600
Completed execution of main method
The "java.lang.ArithmeticException: / by zero" message is written by System.out.println(ae) statement inside the catch block (refer line #14 in listing 8-8). The "Completed fund transfer" message is written by FundTransfer’s transferFunds method (refer line #7 in listing 8-4). The rest of the messages are printed by InternetBanking’s main method (refer listing 8-6).

Figure 8-5 shows the flow of program control when ArithmeticException thrown by Account’s debit method is caught in the debit method itself.
At , InternetBanking’s main method calls FundTransfer’s transferFunds method. At , transferFunds method calls Account’s debit method. At , ArithmeticException results in execution of the catch block’s System.out.println(ae) statement. ArithmeticException transfers program control directly to the catch block; therefore, System.out.println(i) and currentBalance = tempBalance statements are not executed. At , debit method completes execution and the program control returns to the transferFunds method. At , the transferFunds method completes execution and the program control returns to the main method. As both transferFunds and main methods execute successfully, all of their statements are executed.
Figure 8-5 Flow of program control when ArithmeticException is caught in the debit method

NOTE Figure 8-5 shows that the statement contained in the catch block is executed only when ArithmeticException is thrown by int i = 1/0 statement in the try block.
We caught the ArithmeticException thrown in debit method so that the program doesn’t terminate abruptly. But, it doesn’t mean that the program did what it was intended to do. Figure 8-5 shows that currentBalance = tempBalance statement is not executed. So, when we transferred 1400 from xAcc to yAcc account, the current balance of xAcc account remained unchanged at 1000 but the current balance of yAcc increased to 2600.
Hands-on Modify placement of try-catch block
You should note that the placement of try-catch block has an impact on the program behavior. For instance, modify the Account’s debit method such that the try-catch block is placed as shown in the following listing:
Listing 8-9 Account class – try-catch block with a different placement
1     package com.sample;
2
3     public class Account {
4         private int currentBalance;
5         .....
6         public void debit(int amt) {
7             int tempBalance = currentBalance - amt;
8             if (tempBalance < 0) {
9                 try {
10                    int i = 1 / 0; throws ArithmeticException
11                    System.out.println(i); this statement is never executed
12                } catch (ArithmeticException ae) {
13                    System.out.println(ae);
14                }
15            }
16            currentBalance = tempBalance; executed even when ArithmeticException occurs
17        }
18        .....
19    }
The try-catch block in the above listing only encloses the following two statements:
int i = 1/0;
System.out.println(i);
And, the following statement is now after the try-catch block:
currentBalance = tempBalance;
The statement(s) that follow after the try-catch block are executed in the following scenarios:
>  no exception is thrown by the statements in the try block
>  exception thrown by the statements in the try block is caught by the catch block

As ArithmeticException thrown in the try block is caught by the catch block, the currentBalance = tempBalance statement is executed. This means that even if ArithmeticException occurs, the amt amount is subtracted from currentBalance. If you now execute the InternetBanking’s main method, you’ll see the following output:
java.lang.ArithmeticException: / by zero
Completed fund transfer
xAcc’s current balance -400
yAcc’s current balance 2600
Completed execution of main method
The output shows that when 1400 is transferred from xAcc to yAcc account, 1400 is debited from xAcc account and 1400 is credited to yAcc account. This program behavior is incorrect because 1400 was debited from xAcc account even when its current balance was only 1000.
Figure 8-6 shows the program behavior when try-catch block is placed as shown in listing 8-9.
Figure 8-6 The statement currentBalance = tempBalance is executed even when ArithmeticException is thrown
NOTE A statement inside a catch block can also throw an exception. If an exception is thrown from the catch block, the program execution stops and the exception is returned to the calling method.
If the statements enclosed within the try block can throw more than one type of exception, then you can use multiple catch blocks to catch those exceptions.
IMPORT It is recommended that you import the multiple-catch project into your Eclipse IDE.
The following listing shows Sample class that uses multiple catch blocks:
Listing 8-10 Sample class – multiple catch blocks
Project: multiple-catch
Source location: src\com\sample\Sample.java
1     package com.sample;
2
3     public class Sample {
4         private int x;
5         private Car car;
6
7         public void doSomething() {
8             try {
9                 int i = 1 / x; can throw java.lang.ArithmeticException
10                car.getColor(); can throw java.lang.NullPointerException
11            } catch (ArithmeticException ae)
12                System.out.println("exception : " + ae); executed when ArithmeticException is thrown
13            } catch (NullPointerException npe) {
14                System.out.println("exception : " + npe); executed when NullPointerException is thrown
15            }
16        }
17        public void setX(int x) {
18            this.x = x;
19        }
20        public void setCar(Car car) {
21            this.car = car;
22        }
23    }
The values of x (of type int) and car (of type Car) attributes are set via setX (line #17) and setCar (line #20) methods, respectively. The doSomething method assigns value of 1/x to variable i (line #9) and calls Car’s getColor method (line #10).
If we create an instance of Sample and set value of x to 0, java.lang.ArithmeticException is thrown on line #7 when the doSomething method is executed. Similarly, if create an instance of Sample and set car attribute to null, java.lang.NullPointerException is thrown on line #8 when the doSomething method is executed. As we want to catch both the exceptions, a catch block has been defined for each exception type (refer line #11 and #13).
NOTE As only one exception is thrown at a time by a program, only one catch block is executed.
The following listing shows the SampleTest class whose main method creates objects of Sample class and calls their doSomething method:
Listing 8-11 SampleTest class
Project: multiple-catch
Source location: src\com\sample\SampleTest.java
1     package com.sample;
2
3     public class SampleTest {
4         public static void main(String args[]) {
5             Sample sample_1 = new Sample();
6             sample_1.setX(1);
7             sample_1.doSomething();
8
9             Sample sample_2 = new Sample();
10            sample_2.setCar(new Car("someMake"));
11            sample_2.doSomething();
12        }
13    }
In the above listing, we create two instances, sample_1 and sample_2, of Sample class. When a Sample object is created by calling Sample class’s default constructor, the value of x is initialized to 0 and the car attribute is initialized to null. We call sample_1’s setX method (line #6) to set its value of x to 1 and we call sample_2’s setCar method (line #10) to set its car attribute to a Car object.
As sample_1’s car attribute is set to null, call to sample_1’s doSomething method results in NullPointerException (refer line #10 in listing 8-10). Similarly, as sample_2’s x attribute is set to 0, call to sample_2’s doSomething method results in ArithmeticException (refer line #9 in listing 8-10).
If you run SampleTest’s main method, you’ll get the following output:
exception java.lang.NullPointerException
exception java.lang.ArithmeticException: / by zero
The output corresponds to the System.out.println statement contained in each catch block defined in Sample’s doSomething method (refer line #12 and #14 in listing 8-10).
Catching multiple exceptions in a single catch block
Instead of defining a catch block corresponding to each exception type, you can define a single catch block that catches multiple exception types. The following listing shows the modified doSomething method of Sample class that uses a single catch block to catch both NullPointerException and ArithmeticException types:
Listing 8-12 Catching multiple exceptions in a single catch block
1     public void doSomething() {
2         try {
3             int i = 1 / x;
4             car.getColor();
5         } catch (ArithmeticException | NullPointerException ex) {  | separates exception types
6             System.out.println("exception " + ex);
7         }
8     }
In the above listing, catch block specifies that it catches both ArithmeticException and NullPointerException types. The vertical bar | is used to separate different exception types caught by the catch block.
NOTE Using a single catch block for catching exceptions is useful only if you want to execute same set of statements for the caught exceptions
Catching exceptions related by inheritance
By default, a catch block catches all exceptions of the specified exception type and its subtypes. For instance, the following listing shows the modified version of Sample’s doSomething method that catches java.lang.Exception type instead of NullPointerException and ArithmeticException types:
Listing 8-13 Catching multiple exceptions
1    public void doSomething() {
2       try {
3            int i = 1 / x;  can throw java.lang.ArithmeticException
4            car.getColor(); can throw java.lang.NullPointerException
5        } catch (Exception ex) {
6            System.out.println("exception " + ex);
7        }
8    }
The catch block specifies that it catches java.lang.Exception type. As both ArithmeticException and NullPointerException are subtypes of java.lang.Exception, the catch block catches both ArithmeticException and NullPointerException exceptions.

NOTE Both java.lang.ArithmeticException and java.lang.NullPointerException classes inherit from java.lang.RuntimeException, which in turn inherits from java.lang.Exception. This means, ArithmeticException and NullPointerException classes are subtypes of Exception.

When an exception occurs, the first catch block that matches the thrown exception is responsible for handling the exception. In the following listing, if an ArithmeticException is thrown on line #3, it is handled by the first catch block (line #5):
Listing 8-14 The first catch block handles the exception
1     public void doSomething() {
2         try {
3             int i = 1 / x; can throw java.lang.ArithmeticException
4            car.getColor(); can throw java.lang.NullPointerException
5         } catch (ArithmeticException ex) {
6             System.out.println("exception " + ex);
7         } catch (Exception ex) {
8             System.out.println("exception " + ex);
9         }
10    }
The catch block corresponding to java.lang.Exception type (line #7) is executed only when an exception other than ArithmeticException (or its subtype) is thrown.
Now, consider the following listing in which the catch block for java.lang.Exception comes before the catch block for java.lang.ArithmeticException:
Listing 8-15 Exception is caught before ArithmeticException
1     public void doSomething() {
2         try {
3             int i = 1 / x; can throw java.lang.ArithmeticException
4            car.getColor(); can throw java.lang.NullPointerException
5         } catch (Exception ex) {
6             System.out.println("exception " + ex);
7         } catch (ArithmeticException ex) { compilation error
8             System.out.println("exception " + ex);
9         }
10    }
If an ArithmeticException is thrown on line #3, it’ll be caught by the first catch block (line #5) that catches java.lang.Exception. This means, the catch block for ArithmeticException (line #7) will never be executed. As the Java compiler figures out that the catch block for ArithmeticException will never be executed, it reports compilation error on line #7. This shows that the catch blocks must be ordered such that a more general exception (like java.lang.Exception) comes after a more specific exception (like java.lang.ArithmeticException).
Let’s now look at the finally statement block that comes after the catch block.
IMPORT It is recommended that you import finally-block project into your Eclipse IDE.

finally block

The finally block comes after the catch block(s) and is guaranteed to be executed. This means, the finally block is executed when no exception occurs and also when the try or catch block throws an exception.

The following listing shows the Sample class whose doSomething method uses the finally block:
Listing 8-16 Sample class - finally block
Project: finally-block
Source location: src\com\sample\Sample.java
1     package com.sample;
2
3     public class Sample {
4         private int x;
5
6         public void doSomething() {
7             int i = 10;
8             try { =
9                 i = 100 / x; throws ArithmeticException if x is 0
10            } catch (ArithmeticException ae) {
11                System.out.println("exception " + ae);
12            } finally {                                                   
13                System.out.println("value of i " + i); guaranteed to be executed
14            }
15        }
16
17        public void setX(int x) {
18            this.x = x;
19        }
20    }
Sample class defines an instance variable x (of type int) whose value is set using setX method (line #17). The doSomething method defines an int variable i and initializes it to 10 (refer line #7). The value of i is then changed to 100/x (line #9). If x is 0, then the statement i = 100/x will throw java.lang.ArithmeticException. For this reason, the statement i = 100/x is enclosed within the try block. The catch block on line #10 catches the ArithmeticException and writes the exception details to the output. The catch block is followed by a finally block (line #12) which simply writes the value of i to the output.
The following listing shows the SampleTest class whose main method creates two instances (sample_1 and sample_2) of Sample class and calls their doSomething method:
Listing 8-17 SampleTest class
Project: finally-block
Source location: src\com\sample\SampleTest.java
1     package com.sample;
2
3     public class SampleTest {
4         public static void main(String args[]) {
5             Sample sample_1 = new Sample();
6             System.out.println("calling sample_1's doSomething");
7             sample_1.doSomething();
8
9             Sample sample_2 = new Sample();
10            sample_2.setX(2);
11            System.out.println("calling sample_2's doSomething");
12            sample_2.doSomething();
13        }
14    }
We call sample_1’s doSomething method without setting the value of attribute x. As the default value of x is 0, call to sample_1’s doSomething method throws java.lang.ArithmeticException (refer line #9 in listing 8-16). We call sample_2’s doSomething method after setting the value of x to 2. As the value of x is 2, calling sample_2’s doSomething method doesn’t throw any exception.
If you run SampleTest’s main method, you’ll see the following output:
calling sample_1's doSomething
exception java.lang.ArithmeticException: / by zero
value of i 10
calling sample_2's doSomething
value of i 50
The output shows that calling sample_1’s doSomething method results in execution of both catch and finally blocks. And, even though calling sample_2’s doSomething method doesn’t result in an exception, the finally block is still executed.
NOTE A statement inside a finally block can also throw an exception. If an exception is thrown from the finally block, the program execution stops and the exception is returned to the calling method.
Let’s now look at how to create custom exception types and throw them.

8-4 Custom exception types

You can create a checked exception type by extending java.lang.Exception, and you can create an unchecked exception type by extending java.lang.RuntimeException.
NOTE You can create an exception type by directly extending java.lang.Throwable. An exception type created by extending java.lang.Throwable is treated as an unchecked exception. It is recommended that you don’t create a custom exception type by directly extending java.lang.Throwable class. Instead, use java.lang.Exception (for checked exceptions) or java.lang.RuntimeException (for unchecked exceptions).
Let’s now look at a modified version of internet banking application that throws a custom InsufficientBalanceException exception type when the bank account doesn’t have sufficient balance for performing fund transfer.
IMPORT It is recommended that you import the custom-exception project into your Eclipse IDE.
The following listing shows the InsufficientBalanceException class that represents insufficient balance in a bank account:
Listing 8-18 InsufficientBalanceException class
Project: custom-exception
Source location: src\com\sample\InsufficientBalanceException.java
1     package com.sample;
2
3     public class InsufficientBalanceException extends RuntimeException {
4         public InsufficientBalanceException(int accountNumber, int balance) {
5             super("The bank account " + accountNumber + " has balance " + balance);
6         }
7     }
InsufficientBalanceException extends java.lang.RuntimeException; therefore, it’s an unchecked exception type. InsufficientBalanceException’s constructor accepts accountNumber (the bank account number) and balance (current balance in the bank account) as arguments. InsufficientBalanceException’s constructor calls RuntimeException’s constructor (line #5) and passes the exception message. The exception message is stored as an instance variable in the RuntimeException object, and can be accessed by calling the inherited getMessage method of RuntimeException.
The following listing shows the Account class that throws InsufficientBalanceException if the current balance (represented by currentBalance instance variable) is less than the amount being transferred (represented by amt argument passed to debit method):
Listing 8-19 Account class – throwing custom exception
Project: custom-exception
Source location: src\com\sample\Account.java
1     package com.sample;
2
3     public class Account {
4         private int accountNumber;
5         private int currentBalance;
6         .....
7         public void debit(int amt) {
8             int tempBalance = currentBalance - amt;
9             if (tempBalance < 0) {
10                throw new InsufficientBalanceException(accountNumber, currentBalance);
11            }
12            currentBalance = tempBalance;
13        }
14        .....
15    }
On line #8, the debit method stores the result of subtracting amt amount from currentBalance into tempBalance variable. If tempBalance < 0 condition evaluates to true, it means that subtracting amt amount from currentBalance results in negative account balance. For this reason, if tempBalance < 0 evaluates to true, an object of InsufficientBalanceException class is created using the new keyword and thrown using the throw statement (refer line #10).
A throw statement has the following syntax:
throw <a-Throwable-object>;
                  here, <a-Throwable-object> is any object that extends directly or indirectly java.lang.Throwable
If you now open the InternetBanking class (which is same as shown in listing 8-7) of custom-exception project and run its main method, you’ll get the following output:
Exception in thread "main" com.sample.InsufficientBalanceException: The bank account 1 has balance 1000
    at com.sample.Account.debit(Account.java:19)
    at com.sample.FundTransfer.transferFunds(FundTransfer.java:5)
    at com.sample.InternetBanking.main(InternetBanking.java:8)
The output shows that an attempt to transfer 1400 from xAcc to yAcc resulted in InsufficientBalanceException thrown by the Account’s debit method. The exception message "The bank account 1 has balance 1000" was set while creating the InsufficientBalanceException object (refer line #5 of listing 8-18). The JVM obtains the exception message associated with the InsufficientBalanceException object by calling its getMessage method and writes it to the output.
NOTE You can use throw statement inside catch and finally blocks also to throw exceptions.
Let’s look at how the program would have looked if we had defined InsufficientBalanceException as a checked exception.
Hands-on Modify InsufficientBalanceException class to extend java.lang.Exception
The following listing shows the modified InsufficientBalanceException class that extends from java.lang.Exception:
Listing 8-20 InsufficientBalanceException class – a checked exception
1     package com.sample;
2
3     public class InsufficientBalanceException extends Exception {
4         public InsufficientBalanceException(int accountNumber, int balance) {
5            super("The bank account " + accountNumber + " has balance " + balance);
6         }
7     }
As the InsufficientBalanceException class now inherits from java.lang.Exception class, it represents a checked exception. As shown in figure 8-7, you’ll now notice that the Account class shows compilation error on the line where we throw InsufficientBalanceException. Account class shows compilation error because its debit method throws InsufficientBalanceException – a checked exception. The compilation error message is 'Unhandled exception type InsufficientBalanceException'.

We saw in earlier examples that if you don’t catch an unchecked exception, it is simply propagated to the calling method. On the other hand, a checked exception must be caught in the method or specified in the method definition using the throws clause.
Figure 8-7 Account class fails to compile because InsufficientBalanceException is a checked exception
So, for successfully compiling the Account class we must specify that the debit method throws InsufficientBalanceException or catch it in the debit method itself. The following listing shows the modified debit method that specifies that it throws InsufficientBalanceException:
Listing 8-21 Account class’s debit method – throws clause usage
1     public void debit(int amt) throws InsufficientBalanceException {
2         int tempBalance = currentBalance - amt;
3         if (tempBalance < 0) {
4             throw new InsufficientBalanceException(accountNumber, currentBalance);
5         }
6         currentBalance = tempBalance;
7     }
In the above listing, we’ve added the throws clause to the debit method definition. The debit method now clearly indicates that it throws InsufficientBalanceException which the calling method can catch and attempt to recover from it.
NOTE You should note that an unchecked exception represents a programming error (like, division by zero); therefore, a calling method should not attempt to recover from it. For this reason, throw an unchecked exception if you expect that the calling methods can’t recover from it. And, you should throw a checked exception if you expect that the calling methods can recover from it.
Adding throws clause to Account class’s debit method results in compilation error in the FundTransfer class (refer figure 8-8). The line on which we call Account’s debit method shows compilation error because the debit method is defined to throw InsufficientBalanceException checked exception (refer listing 8-21). The transferFunds method must either catch InsufficientBalanceException or specify that it also throws InsufficientBalanceException.

Figure 8-8 FundTransfer class fails to compile because the transferFunds method doesn’t catch InsufficientBalanceException or specify that it throws InsufficientBalanceException
NOTE When InsufficientBalanceException was defined as an unchecked exception, it was not required for FundTransfer’s transferFunds method to catch the exception or specify it using the throws clause. This shows that if a method calls a method that throws a checked exception, the calling method must either catch the checked exception or specify it using the throws clause.

The following listing shows the modified transferFunds method that uses the throws clause to specify that it throws InsufficientBalanceException:
Listing 8-22 FundTransfer class
1     package com.sample;
2
3     public class FundTransfer {
4         public static boolean transferFunds(Account xAcc, Account yAcc, int amt)
5                  throws InsufficientBalanceException {
6             xAcc.debit(amt);
7             yAcc.credit(amt);
8             System.out.println("Completed fund transfer");
9             return true;
10         }
11    }
The FundTransfer class will now compile successfully.
NOTE If a method throws multiple checked exceptions, you can specify comma-separated names of those exceptions in the throws clause.

You’ll now notice that the InternetBanking’s main method shows compilation error (refer figure 8-9) on the line where the call is made to FundTransfer’s transferFunds method. As the FundTransfer’s transferFunds method specifies that it throws InsufficientBalanceException, the main method must either catch the exception or specify it using the throws clause.

Figure 8-9 InternetBanking class fails to compile because it must either catch InsufficientBalanceException or specify that the main method throws it

As we don’t want the InsufficientBalanceException to propagate to the JVM, modify InternetBanking’s main method to catch the exception, as shown here:
Listing 8-23 InternetBanking class – catching InsufficientBalanceException
1     package com.sample;
2
3     public class InternetBanking {
4         public static void main(String args[]) {
5             Account xAcc = new Account(1, 1000);
6             Account yAcc = new Account(2, 1200);
7
8             try {
9                 FundTransfer.transferFunds(xAcc, yAcc, 1400);
10            } catch (InsufficientBalanceException ex) {
11                System.out.println("Failed to transfer money. Reason: --> " + ex.getMessage());
12            }
13            .....
14        }
15    }
In the above listing, call to FundTransfer’s transferFunds method (line #9) is surrounded by try-catch block. The catch block catches InsufficientBalanceException and prints the exception message on the output (line #11). Notice that we’ve explicitly called the getMessage method of InsufficientBalanceException object to obtain the exception message.
If you run InternetBanking’s main method, you’ll get the following output:
Failed to transfer money. Reason: --> The bank account 1 has balance 1000
xAcc’s current balance 1000
yAcc’s current balance 1200
Completed execution of main method
If we had let the InsufficientBalanceException propagate to JVM, the output would have consisted of methods and Java classes that come into picture when InsufficientBalanceException is thrown. The above output is simple to understand and has relevant details that tell why the program failed to transfer money from xAcc to yAcc account. This graceful handling of exceptions is required in real-world Java applications.

QUIZ

8-1: Which of the following statements are true about exceptions?
a)       an unchecked exception represents a programming error
b)      a checked exception represents a recoverable exception
c)       if an exception class extends from java.lang.Exception, then it represents an unchecked exception
d)      if an exception class extends from java.lang.RuntimeException, then it represents a checked exception
e)       java.lang.Error and its subclasses represent unrecoverable exceptions
8-2: Consider the following Calculator class whose calculate method performs calculations on the supplied number:
1     public class Calculator {
2         private int memory;
3
4         public void calculate(int i) {
5             memory = i;
6             memory = memory + 10; increment memory by 10
7             try {
8                 memory = memory / 0; divide memory by 0
9             } catch (ArithmeticException ae) {
10                memory = memory + 10; increment memory by 10
11                memory = memory / 0;  divide memory by 0
12            } finally {
13                memory = memory * 2;  multiply memory by 2
14                memory = memory / 0;  divide memory by 0
15            }
16        }
17
18        public int getMemory() {
19            return memory;
20        }
21    }
What would be the output from executing the following main method?
1     public static void main(String args[]) {
2         Calculator calculator = new Calculator();
3         try {
4             calculator.calculate(5); call Calculator’s calculate method
5         } catch (Exception e) {
6             System.out.println(calculator.getMemory()); print the value of memory variable
7         }
8     }
8-3: Consider the following doSomething method:
1     public void doSomething() {
2         try {
3             Object object = new Rectangle();
4             String string = (String)object; object is downcasted to String
5         } catch(RuntimeException re) {
6             System.out.println("RuntimeException");
7         } catch(ClassCastException cce) {
8             System.out.println("ClassCastException");
9         }
10    }
What will be the output from executing the doSomething method?
a)       "RuntimeException"
b)      "ClassCastException"
c)       "RuntimeException" followed by "ClassCastException"
d)      The program fails to compile
8-4: Consider the following MyException and MyClass classes:
1     public class MyException extends ClassCastException {
2         public MyException() {
3             super("MyException");
4         }
5     }
1     public class MyClass {
2         public void doSomething() {
3             try {
4                  Object object = new Rectangle();
5                  String string = (String)object;
6             } catch(MyException me) {
7                 System.out.println("catching MyException");
8             } finally {
9                 System.out.println("executing finally block");
10            }
11        }
12    }
What would be the output from executing MyClass’s doSomething method?
a)       "catching MyException"
b)      "executing finally block"
c)       "catching MyException" followed by "executing finally block"
d)      MyClass fails to compile
8-5: Consider the following CatchException class in which the catch block catches java.lang.Throwable:
1     public class CatchException {
2         public void doSomething() {
3             try {
4                 int i = 1/0; throws java.lang.ArithmeticException
5             } catch(Throwable throwable) { catches java.lang.Throwable
6                 System.out.println("catching java.lang.Throwable exception");
7             }
8        }
9    }
Which of the following statements are correct about CatchException class?
a)       The class fails to compile because a catch block can only catch exceptions that are of type java.lang.Exception or its subtype
b)      ArithmeticException thrown on line #4 is not caught by the catch block

 

8-5 Summary

In this chapter, we saw how you can throw and catch exceptions. A real-world Java application typically defines some custom exceptions that are specific to the problem domain. For instance, we defined InsufficientBalanceException to represent insufficient balance in bank account. As incorrect placement of try-catch block can result in incorrect result, you should carefully consider what statements of a method should be enclosed within try block, and what does the catch block should do in case an exception occurs.

Comments

Popular posts from this blog