# Handling Exceptions

an introduction to exception handling in Java

You should download this code and follow along!

Consider the following `Fraction`

class (called `BadFraction`

in the code above):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

public class Fraction {
private int num;
private int den;
public static int gcd(int n, int m) {
if (m == 0) return n;
return gcd(m, n % m);
}
Fraction () {
num = 0;
den = 1;
}
Fraction (int num, int den) {
this.num = num;
this.den = den;
reduce();
}
public void reduce () {
int gcd = gcd(num, den);
if (gcd != 0) {
num /= gcd;
den /= gcd;
}
}
public int getNum () {return num;}
public int getDen () {return den;}
public Fraction plus (Fraction f) {
return new Fraction(num * f.den + den * f.num, den * f.den);
}
public Fraction minus (Fraction f) {
return this.plus(f.times(-1));
}
public Fraction reciprocal () {
return new Fraction(den, num);
}
public Fraction times (Fraction f) {
return new Fraction(num * f.num, den * f.den);
}
public Fraction times (int n) {
return new Fraction(num * n, den);
}
public Fraction dividedBy (Fraction f) {
return this.times(f.reciprocal());
}
public boolean equals (Fraction f) {
return (num * f.den == f.num * den);
}
public String toString () {
return (num + " / " + den);
}
}

To test our `Fraction`

class, we can make some `Fraction`

s:

1
2
3

Fraction a = new Fraction(1, 2);
Fraction b = new Fraction(1, 3);
Fraction c = new Fraction(1, 6);

We can do some arithmetic and get the expected results:

1
2
3
4

System.out.println("a + b = " + a.plus(b).toString());
System.out.println("a - b = " + a.minus(b).toString());
System.out.println("a + b - c = " + a.plus(b).minus(c).toString());
System.out.println("c / (a + b) = " + c.dividedBy(a.plus(b)));

produces the following output

1
2
3
4

a + b = 5 / 6
a - b = 1 / 6
a + b - c = 2 / 3
c / (a + b) = 1 / 5

as we’d expect. But something strange happens when we run the following code:

1
2
3
4
5

Fraction oops = a.minus(b).minus(c).dividedBy(a.minus(b).minus(c));
if (oops.equals(a)) {
System.out.println("Huh... (a - b - c) / (a - b - c) == a");
System.out.println("That is strange, because a = " + a.toString());
}

The resulting output is:

1
2

Huh... (a - b - c) / (a - b - c) == a
That is strange, because a = 1 / 2

Why is this so strange? Well, because

\[\frac{a - b - c}{a - b - c} = \frac{1}{2} \Rightarrow 2 (a - b - c) = (a - b - c) \Rightarrow 2 = 1.\]So it seems our program implies that \(2 = 1\)?!?! Well, no. This problem is revealed when we output the value of the fraction \((a - b - c) / (a - b - c)\):

1

System.out.println("(a - b - c) / (a - b - c) = " + oops.toString());

prints

1

(a - b - c) / (a - b - c) = 0 / 0

The real issue is that we divided by zero, and our program just lets us. In what follows, we will show how to use exception handling to fix this problem.

## Exceptions

Exceptions are a way that we can communicate that our program encountered some sort of error or unexpected input. You’ve probably encountered exceptions in your code resulting from mistakes in your code. For example if you have a program with

1
2
3

int a = 1;
int b = 0;
int c = a / b;

your program will compile, but running it will result in:

1
2

Exception in thread "main" java.lang.ArithmeticException: divide by zero
at DivideByZero.main(DivideByZero.java:6)

or something similar. Here, we will describe how to make and use exceptions so that we can deal with these errors in a graceful manner without crashing our programs.

##### Defining new exceptions

Java has many built-in exceptions (see the Java API documentation—note that many of the listed direct subclasses have subclasses themselves!). If none of the exceptions listed there seem appropriate we can define a new exception by defining a subclass of the `Exception`

class. Typically, all we need to do are to define two constructors for our exception that take, respectively, no arguments and a `String`

as an argument.

Here is the complete code for a `DivisionByZeroException`

that we will use for our `Fraction`

class:

1
2
3
4
5
6
7
8
9

public class DivisionByZeroException extends Exception {
public DivisionByZeroException () {
super();
}
public DivisionByZeroException (String message) {
super(message);
}
}

That’s all we have to do to make a new exception class!

##### Throwing exceptions

When we encounter the exception that our code should deal with, we **throw** the exception, using the keyword `throw`

. There are a few places in `Fraction`

where a division by zero error could occur. The first place is in the constructor for Fraction itself. There is currently nothing stopping a programmer from writing `new Fraction(1, 0)`

and carrying on.

To avoid this scenario, we throw a division by zero exception by adding the following lines to the `Fraction`

constructor:

1
2
3

if (den == 0) {
throw new DivisionByZeroException();
}

Whenever a method throws an exception, we must add the exception(s) that could be thrown to the method’s declaration. We do so by adding `throws …`

to the method declaration after the parameter list, where `…`

is the list of exceptions the method could throw. For example, our new constructor becomes:

1
2
3
4
5
6
7
8
9

Fraction (int num, int den) throws DivisionByZeroException {
if (den == 0) {
throw new DivisionByZeroException();
}
this.num = num;
this.den = den;
reduce();
}

To make our exception more informative, we can add a message saying what happened by passing a `String`

to the exception’s constructor, for example

1

throw new DivisionByZeroException("Tried to create Fraction with numerator " + num + " and denominator " + den);

Unfortunately, our work isn’t done yet. If we compile the new `Fraction`

class, we’ll get errors such as:

1
2

Fraction.java:30: error: unreported exception DivisionByZeroException; must be caught or declared to be thrown
return new Fraction(num * f.den + den * f.num, den * f.den);

Line 30 is in our `plus`

method. The problem is that the method calls the constructor for `Fraction`

, which could throw an exception. Thus, `plus`

needs to either “catch” the exception (and figure out how to handle it), or throw the exception back to whatever method called `plus`

in the first place. If we don’t know how to handle the exception within `plus`

, we should opt for the latter option. To this end, we can just change the declaration of `plus`

to indicate that it can throw a `DivisionByZeroException`

as well:

1
2
3

public Fraction plus throws DivisionByZeroException (Fraction f) {
return new Fraction(num * f.den + den * f.num, den * f.den);
}

Then we can do the same with all methods that call the `Fraction`

constructor and `plus`

so that the `Fraction.java`

compiles.

Now let’s try to test the `Fraction`

class with the following `FractionTester`

program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

public class FractionTester {
public static void main (String[] args) throws DivisionByZeroException {
System.out.println("Making some fractions...");
Fraction a = new Fraction(1, 2);
Fraction b = new Fraction(1, 3);
Fraction c = new Fraction(1, 6);
System.out.println("a = " + a.toString() +
", b = " + b.toString() +
", c = " + c.toString());
System.out.println("Doing some arithmetic...");
System.out.println("a + b = " + a.plus(b).toString());
System.out.println("a - b = " + a.minus(b).toString());
System.out.println("a + b - c = " + a.plus(b).minus(c).toString());
System.out.println("c / (a + b) = " + c.dividedBy(a.plus(b)));
System.out.println("Computing (a - b - c) / (a - b - c)...");
Fraction oops = a.minus(b).minus(c).dividedBy(a.minus(b).minus(c));
if (oops.equals(a)) {
System.out.println("Huh... (a - b - c) / (a - b - c) == a");
System.out.println("That is strange, because a = " + a.toString());
}
System.out.println("(a - b - c) / (a - b - c) = " + oops.toString());
}
}

Unfortunately, now we can’t compile `FractionTester`

because we get a bunch of errors about unreported exceptions:

1
2

FractionTester.java:4: error: unreported exception DivisionByZeroException; must be caught or declared to be thrown
Fraction a = new Fraction(1, 2);

We can fix all of these errors by declaring that our main method `throws DivisionByZeroException`

s. It is bad form to have a main method throw exceptions (the whole point of having the exceptions is so that we can handle them), but here is what happens:

1
2
3
4
5
6
7
8
9
10
11
12
13

Making some fractions...
a = 1 / 2, b = 1 / 3, c = 1 / 6
Doing some arithmetic...
a + b = 5 / 6
a - b = 1 / 6
a + b - c = 2 / 3
c / (a + b) = 1 / 5
Computing (a - b - c) / (a - b - c)...
Exception in thread "main" DivisionByZeroException: Tried to create Fraction with numerator 1 and denominator 0
at Fraction.<init>(Fraction.java:14)
at Fraction.reciprocal(Fraction.java:43)
at Fraction.dividedBy(Fraction.java:55)
at FractionTester.main(FractionTester.java:19)

This is progress in the sense that the program at least alerts us that there is a problem with division by zero (unlike before). But this is still bad in the sense that our program is interrupted before we can try to fix the issue.

##### Catching exceptions

In the programs above, exceptions are thrown, but we never attempt to fix or isolate the problem. As a result, when an exception is encountered, the program terminates (albeit with a helpful message indicating where the problem occurred).

If we know how to handle a problem indicated by a thrown exception, we can “catch” the exception by using **try-catch blocks**:

1
2
3
4
5
6

try {
// some code that could throw SomeException
}
catch (SomeException e) {
// code to run if SomeException is thrown
}

When the code in the `try`

block throws `SomeException`

, execution of the `try`

block is stopped, and the code in the `catch`

block is executed. Since the code in the catch block deals with the exception, the method containing the try-catch blocks doesn’t need to throw `SomeException`

itself.

**Note.** We can handle multiple exceptions by having multiple catch blocks:

1
2
3
4
5
6
7
8
9

try {
// some code that could throw SomeException or AnotherException
}
catch (SomeException e) {
// code to run if SomeException is thrown
}
catch (AnotherException e) {
// code to run if AnotherException is thrown
}

Now we can catch the exceptions thrown by `Fraction`

in our `FractionTester`

program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

public class FractionTester {
public static void main (String[] args) {
System.out.println("Making some fractions...");
Fraction a = new Fraction();
Fraction b = new Fraction();
Fraction c = new Fraction();
try {
a = new Fraction(1, 2);
b = new Fraction(1, 3);
c = new Fraction(1, 6);
System.out.println("a = " + a.toString() +
", b = " + b.toString() +
", c = " + c.toString());
}
catch (DivisionByZeroException e){
// Since I defined the Fractions above not to be zero, I'm
// not even going to write any code here. I *know* a
// DivisionByZeroException won't occur
}
System.out.println("Doing some basic arithmetic...");
try {
System.out.println("a + b = " + a.plus(b).toString());
System.out.println("a - b = " + a.minus(b).toString());
System.out.println("a + b - c = " + a.plus(b).minus(c).toString());
System.out.println("c / (a + b) = " + c.dividedBy(a.plus(b)));
System.out.println("1 / (a - b - c) = " + a.minus(b).minus(c).reciprocal());
}
catch (DivisionByZeroException e) {
System.out.println("Oops. We divided by zero! " + e);
}
}
}

Notice that we had to declare `Fraction`

s `a`

, `b`

, and `c`

outside of the first `try`

block, where we called their zero-argument constructors (which do not throw exceptions).

Running the program gives the following output:

1
2
3
4
5
6
7
8

Making some fractions...
a = 1 / 2, b = 1 / 3, c = 1 / 6
Doing some basic arithmetic...
a + b = 5 / 6
a - b = 1 / 6
a + b - c = 2 / 3
c / (a + b) = 1 / 5
Oops. We divided by zero! DivisionByZeroException: Tried to create Fraction with numerator 1 and denominator 0

Things are looking good, but our program can be improved. First of all, since the `Fraction`

constructor throws an exception, we can assume that any `Fraction`

instance does not have a zero denominator after construction. Since `den`

is private and there is no method to set `den`

directly, we can safely assume that adding, subtracting, and multiplying existing `Fraction`

instances will not create `Fraction`

s with zero denominators. Thus we can catch `DivisionByZeroExceptions`

directly in these methods. For example:

1
2
3
4
5
6
7
8

public Fraction plus (Fraction f) {
try {
return new Fraction(num * f.den + den * f.num, den * f.den);
}
catch (DivisionByZeroException e) {
return null;
}
}

Again, we can be certain that the exception we’re “catching” never occurs, so we don’t need to put any code here. We can modify `minus`

and `times`

similarly. The methods `reciprocal`

and `dividedBy`

, however, might create zero denominators (if they are called with an argument whose value is `0`

), so they should still throw exceptions.

Once we’ve made these modifications to `Fraction`

, we don’t need to call `plus`

, `minus`

, or `times`

in `FractionTester`

inside a `try`

block. Now we can separate the “dangerous” statements into their own try-catch blocks so that we can make more specific behavior:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

try {
System.out.println("c / (a + b) = " + c.dividedBy(a.plus(b)));
}
catch (DivisionByZeroException e) {
System.out.println("Oops. You tried to divide " + c.toString() + " by " + a.plus(b).toString() + ". " + e);
}
try {
System.out.println("1 / (a - b - c) = " + a.minus(b).minus(c).reciprocal());
}
catch (DivisionByZeroException e) {
System.out.println("Oops. You tried to take the reciprocal of " + a.minus(b).minus(c).toString() + ". " + e);
}

The resulting modification outputs:

1
2
3
4
5
6
7
8

Making some fractions...
a = 1 / 2, b = 1 / 3, c = 1 / 6
Doing some basic arithmetic...
a + b = 5 / 6
a - b = 1 / 6
a + b - c = 2 / 3
c / (a + b) = 1 / 5
Oops. You tried to take the reciprocal of 0 / 1 DivisionByZeroException: Tried to create Fraction with numerator 1 and denominator 0

Finally, to see that this exception handling actually buys us something, see what happens if we move the first few arithmetic operations to *after* the try-catch blocks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

System.out.println("Doing some basic arithmetic...");
System.out.println("a + b = " + a.plus(b).toString());
try {
System.out.println("c / (a + b) = " + c.dividedBy(a.plus(b)));
}
catch (DivisionByZeroException e) {
System.out.println("Oops. You tried to divide " + c.toString() + " by " + a.plus(b).toString() + ". " + e);
}
try {
System.out.println("1 / (a - b - c) = " + a.minus(b).minus(c).reciprocal());
}
catch (DivisionByZeroException e) {
System.out.println("Oops. You tried to take the reciprocal of " + a.minus(b).minus(c).toString() + ". " + e);
}
System.out.println("a - b = " + a.minus(b).toString());
System.out.println("a + b - c = " + a.plus(b).minus(c).toString());

Now this code gives the following output:

1
2
3
4
5
6
7
8

Making some fractions...
a = 1 / 2, b = 1 / 3, c = 1 / 6
Doing some basic arithmetic...
a + b = 5 / 6
c / (a + b) = 1 / 5
Oops. You tried to take the reciprocal of 0 / 1. DivisionByZeroException: Tried to create Fraction with numerator 1 and denominator 0
a - b = 1 / 6
a + b - c = 2 / 3

This is progress! We did some arithmetic that previously either crashed our program, or (worse!) gave a subtle error without us having any clue why. Now, we can detect mistakes in the program’s input/execution and deal with them in such a way that the program continues to function despite the exception.