|
JavaFAQ Home » Java Lessons by Jon Huhtala

Exception handling with try, catch, and finally blocks
Overview
One of the major differences
between commercial quality programs and those we have written and studied so far
is in their ability to survive various error conditions. For example, it is
relatively difficult to make programs like Microsoft Word or Adobe
Acrobat Reader crash. If they did crash easily, they would not be on the
market for long.
Operating systems in particular
must survive nearly any error that can occur. If the operating system fails, the
entire system is brought down and all currently executing programs come to an
abrupt end. The result can be devastating with work being lost and files being
corrupted. The ability of competing operating systems (such as Windows
and Unix) to detect and recover from errors is a constant source of
debate among their advocates.
In an effort to make software
fail-safe, estimates are that as much as 90% of the code in a commercial product
is there to detect and recover from errors that might never occur. But, it is
best to be prepared.
As a robust language, Java
provides built-in language features, interfaces, and classes that help a
programmer detect and recover from a wide range of conditions that would
otherwise result in program failure.
Some conditions are more severe
than others but all are Throwable objects in Java. The Throwable class is the root class for all errors and
exceptions and is part of the java.lang package. When an error or exception occurs, an object is
constructed that encapsulates the condition and it is "thrown". If and how the
object is "caught" will be covered shortly.
Errors
-
Are encapsulated by the Error class (an extension of
Throwable) and its
descendent classes (such as VirtualMachineError, ThreadDeath, AWTError, etc.)
-
Are serious conditions that a reasonable
application is not expected to detect and from which it is not expected to
recover. For example, an OutOfMemoryError (a descendent of VirtualMachineError) will occur if the JVM has run
out of memory. There is little an application can do about this condition.
-
Are considered abnormal conditions that should
never occur. For that reason, we will not worry about them in our typical
application programs.
...........
Exceptions
-
Are encapsulated by the Exception class (an extension
of Throwable), its many
descendent classes (such as RuntimeException and IOException), and their many descendent classes (such as ArithmeticException, NullPointerException, EOFException, ArrayIndexOutOfBoundsException,
SocketException, etc.).
-
Are less serious conditions that a reasonable
application can anticipate and from which it may recover
-
May result from poor programming. For example, this poorly written program
is a simulation of the old "shell game". The user is asked to pick a number
from 1 to 3 to locate an object stored at random within a three element array.
Unfortunately, the other array elements are null. If the user picks the correct number, they
win. If they don't, a NullPointerException will occur. The user can also generate an
ArrayIndexOutOfBoundsException if they pick a number other than
1, 2, or 3.
public class App {
public static void main(String[] args) {
// Loop
control variable.
char again =
'y';
// Main loop. One array is entered and
processed in each iteration.
while (again == 'Y' ||
again =='y') {
// Instantiate a three
element array and load a single String // at
a random element location.
String[]
strings = new String[3]; int randomIndex =
(int) ((Math.random()*100) %
strings.length); strings[randomIndex] =
"Lucky";
// Ask the user to guess the
element location.
Utility.separator(50,
'>'); System.out.print("Pick a number
from 1 to " + strings.length + ": ");
//
If they guess the element location, display a message.
Otherwise, // an exception will occur to
terminate processing.
if
(strings[Keyboard.readInt() - 1].equals("Lucky"))
{
Utility.skip();
System.out.println(" YOU WIN!!!");
}
// Ask the user if they want to do it
again and repeat the loop as //
requested.
Utility.separator(40,
'='); System.out.print("Again? (Y/N):
"); again =
Keyboard.readChar(); } } }
Note: Run this program
several times and notice the exceptions that occur. Be sure to enter a number
other than 1, 2, or 3 at least once. We will correct these errors
shortly.
The exception handling
technique
-
Involves the use of the try, catch, and finally Java keywords
-
Consists of several steps
-
try a block of code that may result in an
exception being "thrown"
-
Code one or more blocks
designed to automatically catch and handle a specific type of exception if one occurs.
At most, only one of these blocks can be called in a single pass through the
code. If none of the specified exceptions occurs, none of the blocks will be
executed.
-
Optionally code a block
that will finally be
run in ALL situations, whether an exception occurs or not
try
{ statements that may result in an
exception being thrown; } catch
(exception-type1 reference)
{ statements to handle the
exception; } catch
(exception-type2 reference)
{ statements to handle the
exception; } other catch
blocks... finally
{ statements to be ALWAYS executed; }
where exception-typeN is the class name of
the exception to be caught (such as NullPointerException) and reference is its local object reference within the catch block.
Example: The following is a
modified version of the "shell game" program presented earlier. It contains a
try block and two catch blocks. One handles a
NullPointerException and
the other handles an ArrayIndexOutOfBoundsException. No finally block is specified, so logic comes
together after the end of the last catch block.
public class App { public static void
main(String[] args) {
// Loop control
variable.
char again =
'y';
// Main loop. One array is entered and
processed in each iteration.
while (again == 'Y' ||
again =='y') {
// Instantiate a three
element array and load a single String // at
a random element location.
String[]
strings = new String[3]; int randomIndex =
(int) ((Math.random()*100) %
strings.length); strings[randomIndex] =
"Lucky";
// Ask the user to guess the
element location.
Utility.separator(50,
'>'); System.out.print("Pick a number
from 1 to " + strings.length + ": ");
//
"Try" to read their response, use it to index into the
array, // and see if they
win.
try
{
// If they guess the
element location, display a message.
Otherwise, // an exception will
occur.
if
(strings[Keyboard.readInt() - 1].equals("Lucky"))
{
Utility.skip();
System.out.println(" YOU
WIN!!!");
} }
//
This block is automatically executed if a
NullPointerException // occurs to indicate a
null array location.
catch
(NullPointerException err) {
Utility.skip();
System.out.println(" Empty shell - YOU
LOSE!!!");
}
// If an
ArrayIndexOutOfBoundsException occurs, this block
is // automatically executed. It indicates
an invalid number was // used as an
index.
catch
(ArrayIndexOutOfBoundsException err)
{
Utility.skip();
System.out.println(" Invalid number - YOU
LOSE");
}
// Ask the user if they want to do it
again and repeat the loop as //
requested.
Utility.separator(40,
'='); System.out.print("Again? (Y/N):
"); again =
Keyboard.readChar(); } } }
Note: The catch blocks are mutually
exclusive. In a single iteration you may not process within more than one
catch
block.
Special
considerations
public class App { public static void
main(String[] args) { try
{ int x = 3 / 0;
} catch (ArithmeticException err)
{
System.out.println(err.getMessage());
} catch (Exception err)
{ System.out.println("An error has
occurred"); }
} }
will result in the message
"/ by zero" being
displayed because the getMessage() method of an Exception objects and its descendents returns a message
associated with the exception. while,
public class App { public static void
main(String[] args) { try
{ int x = 3 / 0;
} catch (Exception err)
{ System.out.println("An error has
occurred"); } catch
(ArithmeticException err) {
System.out.println(err.getMessage()); }
} }
results in a compile error
that says the second catch block is unreachable.
Because the Exception class is the ancestor
of all other exception classes, a general-purpose catch block may be coded as
catch (Exception err) {
System.out.println(err.getMessage()); }
and may be the only catch block. Alternatively,
this general-purpose catch block may be placed at the end of all other catch blocks to become the
default catch block. It
would automatically be called if an exception is thrown that doesn't match the
more specific exceptions in the preceding catch blocks.
-
If an exception is thrown
for which there is no corresponding catch block (either a specific exception type or an ancestor
exception type), the JVM "unwinds the stack". It terminates the currently
executing method and looks backward through the call stack looking for a catch block that can handle the
exception. If none is found, the JVM itself is terminated and the application
ends.
-
No actual processing is
required to "catch" an exception. For example, the JVM will permit processing
to continue if a catch
block like the following is coded.
catch (Exception err) {}
As far as the JVM is
concerned, the exception has been handled.
Exceptions that descend from
RuntimeException are NOT
checked by the compiler. Programs that might fail due to such exceptions do
not require try and catch blocks.
-
Calling a method that might
throw a checked exception
must be called within a try block and must catch the thrown exception (or an ancestor) in order to compile.
Throwing an exception will be covered in the next lesson.
-
A try, catch, finally sequence can be nested anywhere within another try, catch, finally sequence.
-
A catch block must have a corresponding try block. It can not stand
alone. Similarly a finally block must have a corresponding try block. The compiler detects such errors.
-
The compiler will permit a
try block with no catch blocks if a finally block is coded. If an
exception occurs, however, the finally block will execute and then the stack will be unwound.
For example,
public class App { public static void
main(String[] args) { try
{ int x = 3 / 0;
} finally {
System.out.println("I'm about to unwind"); }
} }
compiles fine. When
executed, however, an uncaught ArithmeticException occurs. The finally block is executed prior to unwinding the
stack.
Lab exercise for Ferris
students
E-mail your answers to this
assignment no later than
the due date listed in the class schedule.
Review questions
-
Assuming all unseen code is
correct, which of the following will be part of the output displayed by
executing the following statements? The line numbers are for reference
purposes only. (choose four)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
try
{ int[] numbers = new int[3];
System.out.println("Message 1"); numbers[3] = 5;
System.out.println("Message 2"); } catch
(ArrayIndexOutOfBoundsException err) {
System.out.println("Message 3"); } catch (Exception err)
{ System.out.println("Message 4"); } finally
{ System.out.println("Message
5"); } System.out.println("Message
6"); |
-
Message 1
-
Message 2
-
Message 3
-
Message 4
-
Message 5
-
Message 6
-
Assuming all unseen code is
correct, what will be displayed when the following statements are executed?
The line numbers are for reference purposes only.
1 2 3 4 5 6 7 8 9 10 11 |
try
{ StringBuffer[] s = new StringBuffer[10];
s[0].reverse(); } catch (ArrayIndexOutOfBoundsException err)
{ System.out.println("Message 1"); } catch (Exception
err) { System.out.println("Message
2"); } System.out.println("Message
3"); |
-
the statements will not
compile
-
the program will terminate
with nothing being displayed
-
Message 1 Message 3
-
Message 2 Message 3
-
Message 3
-
Assuming all unseen code is
correct, what will be displayed when the following statements are executed?
The line numbers are for reference purposes only.
1 2 3 4 5 6 7 8 9 10 |
try
{ double x = 17.5 / 0.0; } catch (Exception err)
{ System.out.println("Message 1"); } finally
{ System.out.println("Message
2"); } System.out.println("Message
3"); |
-
the statements will not
compile
-
the program will terminate
with nothing being displayed
-
Message 1 Message 2 Message 3
-
Message 2 Message 3
-
Message 3
-
Assuming all unseen code is
correct, what will be displayed when the following statements are executed?
The line numbers are for reference purposes only.
1 2 3 4 5 6 |
try
{ int x = 3 / 0; } catch (Exception err)
{ } System.out.println("Message
1"); |
-
the statements will not
compile
-
the program will terminate
with nothing being displayed
-
Message 1 Printer Friendly Page
Send to a Friend
..
Search here again if you need more info!
|