An
exceptional
condition
is a problem that prevents the continuation of the method or scope that
you’re in. It’s important to distinguish an exceptional condition
from a normal problem, in which you have enough information in the current
context to somehow cope with the difficulty. With an exceptional condition, you
cannot continue processing because you don’t have the information
necessary to deal with the problem
in
the current context
.
All you can do is jump out of the current context and relegate that problem to
a higher context. This is what happens when you throw an exception.
A
simple example is a divide. If you’re about to divide by zero, it’s
worth checking to make sure you don’t go ahead and perform the divide.
But what does it mean that the denominator is zero? Maybe you know, in the
context of the problem you’re trying to solve in that particular method,
how to deal with a zero denominator. But if it’s an unexpected value, you
can’t deal with it and so must throw an exception rather than continuing
along that path.
When
you throw an exception,
several things happen. First, the exception object is created in the same way
that any Java object is created: on the heap, with
new.
Then the current path of execution (the one you couldn’t continue,
remember) is stopped and the handle for the exception object is ejected from
the current context. At this point the exception-handling mechanism takes over
and begins to look for an appropriate place to continue executing the program.
This appropriate place is the
exception
handler
,
whose job is to recover from the problem so the program can either try another
tack or simply continue.
As
a simple example of throwing an exception, consider an object handle called
t.
It’s possible that you might be passed a handle that hasn’t been
initialized, so you might want to check before trying to call a method using
that object handle. You can send information about the error into a larger
context by creating an object representing your information and
“throwing” it out of your current context. This is called
throwing
an exception
.
Here’s what it looks like:
if(t
== null)
throw new NullPointerException();
This
throws the exception, which allows you – in the current context –
to abdicate responsibility for thinking about the issue further. It’s
just magically handled somewhere else. Precisely
where
will
be shown shortly.
Exception
arguments
Like
any object in Java, you always create exceptions on the heap using
new
and a constructor gets called. There are two constructors in all the standard
exceptions; the first is the default constructor, and the second takes a string
argument so you can place pertinent information in the exception:
if(t
== null)
throw new NullPointerException("t = null");
This
string can later be extracted using various methods, as will be shown later.
The
keyword
throw
causes a number of relatively magical things to happen. First it executes the
new-expression
to create
an
object that isn’t there under normal program execution, and of course,
the constructor is called for that object. Then the object is, in effect,
“returned” from the method, even though that object type
isn’t normally what the method is designed to return. A simplistic way to
think about exception handling is as an alternate return mechanism, although
you get into trouble if you take that analogy too far. You can also exit from
ordinary scopes by throwing an exception. But a value is returned, and the
method or scope exits.
Any
similarity to an ordinary return from a method ends here, because
where
you return is someplace completely different from where you return for a normal
method call. (You end up in an appropriate exception handler that might be
miles away – many levels lower on the call stack – from where the
exception was thrown.)
In
addition, you can throw any type of
Throwable
object that you want. Typically, you’ll throw a different class of
exception for each different type of error. The idea is to store the
information in the exception object
and
in the type of exception object chosen, so someone in the bigger context can
figure out what to do with your exception. (Often, the only information is the
type of exception object, and nothing meaningful is stored within the exception
object.)