Exceptions - More

Kinds of Exceptions

There are many exceptions, but they can be put
into two groups: checked exceptions and unchecked exceptions.
There is some controversy about which type you should use.
A discussion of some of the issues can be found at
Java theory and practice: The exceptions debate.

Unchecked Exceptions -- These exceptions are usually something
that should have been prevented by more careful programming.
For example, you should never get NullPointerException
or ArrayIndexOutOfBoundsException.
If you do, there is something wrong with your program, and you
need to fix it. You usually don't catch unchecked exceptions.
Instead, fix your program so it can't produce one of these.
However, NumberFormatException is the one exception of this type
that is usually caught.

Checked Exceptions -- These are usually errors in the input data.
The programmer has no control over the input the user gives you,
eg, file names, .... If the user gives you a bad
value, it may cause an exception when you use it.
You need to check for bad input using a try statement.

Use exceptions for exceptional conditions, NOT normal control flow

Probably most of your student programming has been "Happy Trails"
style, where you didn't have to worry much about handling errors.
But error handling is really a big deal in most real programs, and exceptions
play a central role in dealing with errors.

All experienced programmers agree that using exceptions for normal processing flow is wrong.
Exceptions should only be used only for errors or unusual conditions,
and the equivalent if tests should be used for normal processing.
There are good reasons for this.

Slow. Exceptions are very slow. When an exception
occurs, the Java runtime system works its way up the
call stack (you might be surprised at how deep this can get), identifying
each source statement at which a call was made, and building a string
that reports this. This string is then used in creating the exception
object that is thrown. This is not fast.

Readability. Experienced programmers expect exceptions
to have something to do with errors, so it is very uncomfortable to read code where
it is used for normal flow. A programmer has to stop and examine the
code in the try clause to see what might have caused the exception.

Here are examples where beginning programmers used exceptions, but should
NOT have. These are all done to either speed execution (which they do not) or
simplify code (which they arguably do not).

Example: Test for end of array index range

You might wonder how inefficient this is because the loop must
compare the index with the array size 1000 times, but only
the final test is important. Because Java always checks the subscript
range anyway, why not make use of its check?

Exceptions are so slow that this won't be faster unless the
array is extremely large (much, much larger than 1000).

Avoiding edges in looking for adjacent array cells.

Problem: You must invert the values in a cell in a rectangular grid
and its non-diagonally adjacent cells.
The difficulty is in dealing with the edge cases, where you must avoid
referencing non-existent adjacent cells.

Two alternate definitions of a method are given, one uses exceptions
and the other uses if
to handle the boundary violation cases.
The exception solution is very inefficient
and might be very hard to interpret by the reader. The difficulty
is increased because the writer chose to use the Exception class
instead of ArrayIndexOutOfBoundsException. The use of Exception
suggests that it is designed to catch other exceptions too.
if the body of the try had been larger, it might have been very
difficult decide exactly which exception is being caught. Do you see
which other exception could be thrown by the code, at least in
principle?

Another solution to avoid edge cases is to define
extra rows and columns of boundary cells, and translate the subscripts,
thereby replacing the if tests with two additions.
This requires translating subscript references in all methods. If the
class is properly encapsulated, users of the class will not know about it.

Other examples

There are numerous cases in addition to subscription where the use of
exceptions is entirely inappropriate.

Danger from the intermediate layers - finally

Exceptions provide a good infrastructure for error processing.
The simplicity of throwing an exception at a deep level and catching
it at a high level may generate problems at the intermediate, skipped,
levels. Did any of these methods leave any part of a data structure
or resource in an inconsistent state?
Each place that this may be true of needs to enclose critical code
in a try...finally block.