20. Exceptions
Exceptions provides a way to logical separate the regular code and what to do in an exceptional situation
They make it easy to propagate the exception up the call stack such that the situation can be managed in a desired place
They also allow for differentiating between exception types and how to deal with them specifically
20.1. Errors
In Java, there are two classes of throwable objects
A throwable object is one that can be thrown with a
throw
statement
Errors are one of the two throwable classes
Errors are typically for unrecoverable situations
They’re generally very abnormal situations
Typically, these are not to be caught and handled
Errors and regarded as unchecked for the purpose of compile-time checks
To understand why these are not caught, consider Java’s OutOfMemoryError
Gets thrown if the Java Virtual Machine (JVM) cannot allocate enough memory for the creation of a new object
If the JVM runs out of memory, there is nothing the program can do to resolve this situation
20.2. Throwing an Exception
Several methods written so far have thrown exceptions
Below are the
remove
andremoveFirst
methods from theArraySortedBag
implementationremove
does not throw an exception, butremoveFirst
will if trying to remove from an empty bag
121 @Override
122 public boolean remove(T element) {
123 if (!contains(element)) {
124 return false;
125 }
126 int index = find(element);
127 shiftLeft(index);
128 rear--;
129 return true;
130 }
131
132 @Override
133 public T removeFirst() {
134 if (isEmpty()) {
135 throw new NoSuchElementException("Empty bag");
136 }
137 T returnElement = bag[0];
138 shiftLeft(0);
139 rear--;
140 return returnElement;
141 }
The exception being thrown by
removeFirst
,NoSuchElementException
, is a subclass ofRuntimeException
It is an unchecked exception, so the method does not need to include a
throws NoSuchElementException
in the method signature
The motivation for using an exception in
removeFirst
is, when removing from an empty bag, what should happen?Perhaps this means some critical error happened and the program must stop immediately
Or maybe the program using the bag can just ignore the exception and carry on
Either way, as the writers of the
ArraySortedBag
, it is not possible to know how the user of theArraySortedBag
should address the situationAll that can be done is to throw the exception to inform the user that something exceptional happened
One may wonder why the more general
remove
does not throw an exceptionThis is because
The return type of the general
remove
is aboolean
false
is a reasonable value to return to communicate that theremove
was not successful
The expected return value of
removeFirst
is typeT
— the actual first thing in the bagThere is no obvious explicit way to communicate a failure with the returned value
One could return null or some other special value, but exceptions are a more appropriate tool for this scenario
Ultimately, however, it would not be wrong to have the general
remove
throw an exception in this situationIn the end it is a design decision
20.2.1. Messages
Notice the string provided the the exception’s constructors
"Empty bag"
The string is the message the exception provide to give details on the exceptional situation
Consider how an
ArrayIndexOutOfBoundsException
provides details on the index used that caused the exception
20.3. Catching Exceptions
If someone is using the
ArraySortedBag
implementation two years from now, it’s not possible to know what they should do to manage the exceptional situationsThe users of the
ArraySortedBag
class will need to deal with them as they see fitWhat should be done if calling
remove
on an emptyArraySortedBag
?What should be done if calling
remove
when the element does not exist within theArraySortedBag
?
20.3.1. Ignore
Maybe this doesn’t matter and they don’t even try to catch the exception
If the exception is thrown, their program will crash, but this doesn’t matter to them
1// I know this may throw an exception, but whatever
2bag.remove(element);
Since the exception is not caught here, the exception would be propagated to the calling method
This exception will keep being propagated to the calling methods until it is either
Caught somewhere
The
main
method propagates the exception and the program crashes
20.3.2. Stop Immediately
Maybe they need to stop the execution of the code immediately
They are running medical equipment that delivers radiation therapy
1try {
2 bag.remove(element);
3} catch (NoSuchElementException e) {
4 someCleanUpMethod();
5 System.exit(1);
6}
20.3.3. Carry On
Maybe they can catch it, print out the stack trace, and then carry on and ignore the issue
The program keeps the spaceship running, so it better not crash
1try {
2 bag.remove(element);
3} catch (NoSuchElementException e) {
4 System.out.println("Caught an Exception");
5 e.printStackTrace();
6}
20.3.4. Rethrow
Perhaps we want to catch the exception and then rethrow it as something more appropriate for our context
1try {
2 bag.remove(element);
3} catch (NoSuchElementException e) {
4 throw new MySpecificException(e);
5}
20.4. Catching Different Exception Types
It is possible that the code being called may throw different exception types
These can be individually caught and handled accordingly
The general idea is as follows
1try {
2 mayThrowVariousExceptions();
3} catch (SomeExceptionA e) {
4 handleSomeExceptionA();
5} catch (SomeExceptionB e) {
6 handleSomeExceptionB();
7} catch (SomeExceptionC e) {
8 handleSomeExceptionC();
9} finally {
10 codeThatWillAlwaysRun();
11}
With multiple
catch
statements, the exception class hierarchy must be consideredAlways order the
catch
statements from most specific to most generalFor example
IOException
andFileNotFoundException
1// This is bad
2try {
3 ...
4} catch (IOException e) {
5 ...
6} catch (FileNotFoundException e) {
7 ...
8}
Since
FileNotFoundException
is a subclass ofIOException
, if aFileNotFoundException
is thrown, the firstcatch
statement will catch itIn this scenario, it would not be possible for the code within the second
catch
statement to ever runThis is easily fixed by switching the order of the
catch
statements
20.4.1. Finally
Sometimes it is necessary to have some code run regardless of if an exception was thrown or which exception was caught
The
finally
keyword is used to specify code to be run no matter what happensEg. Closing files
20.5. For Next Time
Go back and read Chapter 3 Section 5
2 pages