If a Java program attempts to carry out an illegal operation,
it does not necessarily halt processing at that point. In most
cases, the JVM provides for the possiblity of catching
the problem and recovering from it. To emphasize that such problems
are not fatal, the term exception is used rather than error.
For example, what if by accident we put a non-numeric string
into an applet tag parameter and it is passed to the wrapper
method Integer.parseInt()
as shown below:
class
myApplet extends Applet
{
....
init ()
{
String
int_string = getParameter ("intNumber");
// If
the parameter returned is not a
// numeric string, there will
be a problem:
int
data =
Integer.parseInt
(int_string);
aMethod
(data);
}
} |
In this case, a Java run-time exception
would be generated and the applet would halt.
Java exception handling provides for a systematic way
for the user to respond to such errors and to decide on an appropriate
response rather than simply letting the program come to a stop.
Without an exception handling system built-in to the language,
you would have to write your own routine to test the string for
numeric numbers. Similarly, for other possible errors you would
need to write special code to catch them before they caused an
error.
For example, in the code below we create a special method to
test if a String
holds a valid integer value before the string goes to the parseInt
method.
...
String int_string
= getParameter ("intNumber");
if
(testIfInt
(int_string))
Integer.parseInt
(int_string);
else
{
ErrorFlag = MY_ERROR_BAD_FORMAT;
return
-1;
}
boolean
testIfInt (String
str)
{
... code
to test characters for numbers ..
}
... |
Thankfully, we can avoid all of this extra coding
and instead use the Java try{}catch(Exception
e){}
operation to handle exceptions. In the following code segment,
for example, we surround the parseInt
method invocation with a try-catch
pair.
String
int_string
= getParameter ("intNumber");
try
{
int
data = Integer.parseInt (int_string);
aFunctionSetup
(data);
}
catch (NumberFormatException
e)
{
flag = -1;
} |
Here, the Integer
class method parseInt
throws an instance of the NumberFormatException
class if the string passed does not represent a valid integer
number.
If the intString is not a valid integer string, the processing
will jump from the parseInt
line to the code in the catch
code body. Here, the flag
= -1; statement would execute.
Generating Exceptions
How does the parseInt
method generate an exception? If we looked inside the code of
the parseInt method we would see something like the following:
public
static int
parseInt (String s, int
radix)
throws NumberFormatException {
{
...
...code to check if the string is a
number and if
...it isn't then:
throw
new NumberFormatException
(s);
...
}
|
The throws NumberFormatException
phrase in the method signature indicates that the method includes
a throw
statement of that type somewhere in the method code. We see
here a throw
statement creates an instance of the exception and causes
the routine to return with this exception to be caught in
a try-catch
in the method that invoked it.
Or, alternatively the invoking method must include
a throws
NumberFormatException in its own method signature so
that the method that invoked it will either catch that exception
or throw the exception itself. Exceptions can thus be passed
up the line, so to speak, until a method finally catches
it.
The constructors for an exception may include
arguments with which you can pass useful information about
the circumstances of the exception. The catch code can then
examine this info using methods for the particular type of
exception.
Generating Exceptions
Java divides exceptions into two categories:
- General exceptions
- Run-time exceptions
The general exceptions (also called checked exceptions)
must be handled. That is, a try-catch
must either be nested around the call to the method that throws
the exception or the method signature must include a
throws
clause for this exception. (Then other methods that invoke this
method must then catch the exception or throw it up the line.)
The compiler will throw an error message if it detects an uncaught
exception and will not compile the file.
The run-time exceptions do not have to be caught. This
avoids requiring that a try-catch
be place around, for example, every integer division operation
to catch a divide by zero or around every array variable to
watch for indices going out of bounds.
However, you should handle possible run-time exceptions if
you think there is a reasonable chance of one occurring. In
the above string parsing example, the NumberFormatException
extends (we discuss subclassing in Chapter
4) RuntimeException
so it is optional to catch this error.
You can use multiple catch clauses to catch the different kinds
of exceptions that code can throw as shown in this snippet:
try
{
...
some code...
}
catch (NumberFormatException e)
{
...
}
catch (IOException e)
{
...
}
catch (Exception e)
{
...
}
finally //
optional
{
...this
code always executed even if
no exceptions...
}
|