Some reader favorites:
EJB fundamentals and session beans
Create a scrollable virtual desktop in Swing
Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API
Last month's Java 101 article introduced you to exceptions. You learned that an exception diverges from normal execution and observed how C, C++, and Java programs handle exceptions. This month, I delve into Java's throw-object/catch-object exception-handling technique by focusing on that technique's exceptions class hierarchy, statements and clauses, and various rules. After completing this article, you will be able to incorporate Java's throw-object/catch-object exception-handling technique into your programs.
Read the whole series on exception handling:
Java's throw-object/catch-object exception-handling technique includes an exceptions class hierarchy. Class Throwable resides at the top of that hierarchy, and the Exception and Error subclasses, which identify the hierarchy's program- and JVM-related exception class subhierarchies (respectively), reside
immediately below -- as the figure below illustrates.

The exceptions class hierarchy organizes itself around three main classes
The exceptions class hierarchy associates with a StackTraceElement class, which lets you trace the method-call stack when an exception occurs. After exploring Throwable, Exception, and Error, I explore StackTraceElement and show how to extend the exceptions class hierarchy to suit your program's requirements.
C++ lets any class represent an exception type. In contrast, Java permits only java.lang.Throwable and Throwable subclasses to represent those types. Apart from Object, an exception object's innermost layer is the Throwable layer. For that reason, you must familiarize yourself with the Throwable class.
Throwable possesses four constructors: Throwable(), Throwable(String message), Throwable(String message, Throwable cause), and Throwable(Throwable cause). The constructors reveal two facts about exception objects. First, you can associate a message with an exception object's
Throwable layer. That message describes the exception's nature in human-readable terms, and a program can present that message to the
program's user. Second, you can wrap one exception object inside another exception object. The wrapped exception object is
called a cause because the wrapped object's presence causes an exception handler to create a second, different exception object that wraps
itself around the wrapped object. A detailed examination of Throwable's constructors shows the following:
Throwable() initializes an exception object's Throwable layer to no message and no cause
Throwable(String message) initializes the Throwable layer to the contents of the String object that message references (and no cause)
Throwable(String message, Throwable cause) initializes the Throwable layer to the specified message and causeThrowable(Throwable cause) initializes the Throwable layer's message to the cause's message (if there is a message) and the specified causeThrowable also possesses eleven methods: getMessage(), getLocalizedMessage(), getCause(), initCause(Throwable cause), fillInStackTrace(), getStackTrace(), printStackTrace(), printStackTrace(PrintStream ps), printStackTrace(PrintWriter pw), setStackTrace(StackTraceElement [] stackTrace), and toString().
The getMessage() method returns a String reference to the Throwable layer's message. If that message does not exist, null returns. By default, getLocalizedMessage() calls getMessage() and passes that method's return value to whatever code calls getLocalizedMessage(). You can tailor getLocalizedMessage() to return the message in the user's written language by overriding that method in appropriate Throwable subclasses.
The getCause() method returns a reference to the Throwable layer's cause. In the case of no cause, getCause() returns null. The initCause(Throwable cause) method provides an alternate approach to initializing the cause. That method initializes the cause to the reference in that
method's cause argument.
| Tip |
|---|
Not all legacy exception classes contain constructors that take cause arguments. If you need to store a cause in some exception
object's Throwable layer and no constructor takes a cause argument, call that object's inherited initCause(Throwable cause) method. Remember, you can call that method only once. Furthermore, initCause(Throwable cause) throws a java.lang.IllegalArgumentException object if a reference to the calling object passes as an argument via cause. Finally, initCause(Throwable cause) throws a java.lang.IllegalStateException object if a call has already been made to that method, the Throwable(String message, Throwable cause) constructor, or the Throwable(Throwable cause) constructor.
|
Throwable dedicates six methods to working with a stack trace -- a sequence of method-call stack frames (where each stack frame describes an incomplete method call) and related source
code information that identify the location of code responsible for throwing an exception object. fillInStackTrace() records the current stack trace in a private Throwable field. (Various Throwable methods call fillInStackTrace() behind the scenes.) The getStackTrace() method returns the contents of that field, which is an array of StackTraceElement objects. An exception handler can access that array and call StackTraceElement methods to help recover from an exception. (I discuss StackTraceElement's methods later in this article.) The three printStackTrace() methods print the stack-trace information in a suitable format on the standard error stream, a PrintStream stream, or a PrintWriter writer. (I discuss streams and writers in a future article.) Method setStackTrace(StackTraceElement[] stackTrace) lets you replace the current stack trace with a new stack trace, which stackTrace specifies.
Finally, Throwable overrides toString() to return a brief exception object description. You will see examples of toString() and other Throwable methods later in this article.
Throwable's java.lang.Exception subclass serves as the root class of Throwable's program-related exception class subhierarchy. To describe an exception that originates from a program, such as a failed
attempt to write to a file or an attempt to access a nonexistent array element, either the program or the JVM creates an object
from a class in that subhierarchy. Examine the following list of exception class names and descriptions to familiarize yourself
with the Exception subhierarchy's classes:
java.lang.CloneNotSupportedException: This class's objects describe attempts to call the clone() methods on objects whose classes do not directly (or indirectly, through superclasses) implement the Cloneable interface
java.io.FileNotFoundException: A java.io.IOException subclass, this class's objects describe failed attempts to open files
java.lang.InterruptedException: This class's objects describe interruptions to sleeping or waiting threads (which I'll discuss next month)
java.lang.ArrayIndexOutOfBoundsException: This class's objects describe attempts to access nonexistent array elements
java.lang.ArithmeticException: This class's objects describe attempts to divide integers by integer value zero
java.lang.NullPointerException: This class's objects describe attempts to access object fields or call object methods via object reference variables that
contain null values
The previous list's first three classes represent different kinds of checked exceptions -- exceptions that a program must handle. To ensure the program handles the exceptions, the compiler checks the source code. In contrast, the list's last three classes represent different unchecked exceptions -- exceptions that a program doesn't need to handle. The compiler doesn't need to verify unchecked exception handling.
| Note |
|---|
Exception's java.lang.RuntimeException subclass and all RuntimeException subclasses identify different unchecked exception types. The JVM usually creates objects from those classes. All other Exception classes, including Exception, identify different checked exception types, and program code creates objects from those classes.
|
Programs must handle checked exceptions because programs can't guarantee such exceptions won't occur. How can a program guarantee it can write to a file?
The compiler does not require programs to handle unchecked exceptions for the following reasons:
Keep in mind that Exception subclass names end with the word Exception. That convention distinguishes Exception subclasses from Error subclasses.
| Tip |
|---|
Never create objects from the Exception class because an exception handler can't distinguish between the different exceptions those objects represent. (Operator
instanceof proves useless in such situations.) To avoid that problem, always create exception objects from appropriate Exception subclasses (except for RuntimeException). The subclass's name tells you if that class is appropriate. For example, use FileNotFoundException to describe exceptions that arise from not finding files.
|
Throwable's java.lang.Error subclass serves as the root class of Throwable's JVM-related exception class subhierarchy. To describe an exception that originates from the JVM, such as the JVM running
out of memory, the JVM creates an object from a class in that subhierarchy. JVM exceptions prove serious and often terminate
the JVM.
I use the term error to distinguish JVM-related failure from program-related failure. Examples of error classes include java.lang.AssertionError, java.lang.ThreadDeath, and java.lang.VirtualMachineError. Not all error classes end with Error.
JVM errors belong to the unchecked exception category because a program can do little, if anything, to fix a JVM error. Also,
don't create your own Error subclasses or try to handle JVM errors. The resulting program will probably prove unstable.
When your code must access stack-trace data (file names, source line numbers, method names, and so forth), that code can call
Throwable's getStackTrace() method. The getStackTrace() method returns an array of references to java.lang.StackTraceElement objects -- where each object describes one stack frame in the stack trace.
Code can call StackTraceElement methods to access stack-trace data. Methods include getClassName(), getFileName(), getLineNumber(), getMethodName(), and isNativeMethod(). Each method returns information relevant to the stack frame associated with the StackTraceElement object.
What does stack-trace data look like? If you work with Sun Microsystems' SDK tools in a command-line environment, you probably
see the stack-trace data produced by the printStackTrace() methods. If not, let's see if we can create some stack-trace data:
Listing 1. SortIntegerArray1.java
// SortIntegerArray1.java
class SortIntegerArray1
{
public static void main (String [] args)
{
int numbers [] = { 22, 13, 5, 76, 3 };
sort (numbers);
for (int i = 0; i < numbers.length; i++)
System.out.println (numbers [i]);
}
static void sort (int [] x)
{
for (int i = 0; i < x.length-1; i++)
for (int j = 0; j < x.length-i; j++)
if (x [j] > x [j+1])
{
int temp = x [j];
x [j] = x [j+1];
x [j+1] = temp;
}
}
}
SortIntegerArray1 attempts to sort (order) a small integer array's contents into ascending order. However, the source code features a problem.
After compiling that code and running the resulting class file, you encounter the following stack-trace data:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at SortIntegerArray1.sort(SortIntegerArray1.java:19)
at SortIntegerArray1.main(SortIntegerArray1.java:9)
The stack-trace data identifies ArrayIndexOutOfBoundsException as the thrown exception object. Because ArrayIndexOutOfBoundsException signifies an unchecked exception arising from flawed code, the JVM creates an object from that class (behind the scenes)
and searches for an appropriate exception handler. Although the program can provide that exception handler and receive the
exception object, it chooses not to do so. When a program doesn't receive an exception object, the JVM's default exception
handler accepts that responsibility: it receives that object and calls printStackTrace() to print a stack trace -- which is what you see above.
The two lines that start with at refer to a pair of stack frames on the method-call stack. Each stack frame describes a method that has not completed its
execution when an exception occurs. From the previous output, you see that neither main() nor sort() (which main() called) is complete. Furthermore, you see the corresponding source code lines where main() called sort() and where sort()'s attempt to access an invalid array element led to the exception.
Now that you know something about StackTraceElement, that class's methods, and what stack-trace data looks like, you probably want to experiment with that class. But first,
you need to understand a few more concepts. After presenting those concepts, I give you a chance to work with StackTraceElement.
The exceptions class hierarchy includes a rich assortment of exception classes. When you need an exception class, you should
first search that hierarchy for an appropriate class. If you cannot find an appropriate class or if you need a class resembling
an existing class, you extend that hierarchy with a new class. Where does the new class fit within the overall class hierarchy?
You must ask yourself if the class describes a checked exception or an unchecked exception. Assuming the answer is checked
exception, the class appears within the Exception subhierarchy -- but not within that subhierarchy's RuntimeException portion. However, if the answer is unchecked exception, the class appears within the RuntimeException subhierarchy. Because you shouldn't handle unchecked exceptions that describe JVM failures, ignore the Error subhierarchy. To clarify this discussion, I present the following two examples:
Throwable layer and record the integer-based response code in a private field of each class. You avoid duplicating response code fields
by introducing a generic superclass that declares that field and extendes that class with POP3 and SMTP exception subclasses.
The following code fragment demonstrates:class EmailException extends Exception
{
private int responseCode;
EmailMessage (int responseCode, String message)
{
// Call Exception(String message), which calls Throwable(String message).
super (message);
this.responseCode = responseCode;
}
int getResponseCode ()
{
return responseCode;
}
}
class POP3Exception extends EmailException
{
}
class SMTPException extends EmailException
{
}
EmailException extends Exception because sometimes SMTP- and POP3-related exceptions arise from reasons other than flawed code -- perhaps the SMTP or POP3
program stops running during a communication session. As a result, POP3Exception and SMTPException identify different checked exceptions. (I'll discuss email, POP3, and SMTP in a future article.)
Overflow and Underflow classes. Because overflow and underflow exceptions indicate flawed code, they represent unchecked exceptions. That implies
Overflow and Underflow subclass RuntimeException, as the following code fragment demonstrates:class Overflow extends RuntimeException
{
}
class Underflow extends RuntimeException
{
}
Because Overflow and Underflow lack duplicate code, you neither need to introduce a new class that extends RuntimeException nor have Overflow and Underflow subclass that new class.
The previous section referred to throwing an exception object. What does that phrase mean? For an answer, consider this: When the JVM detects an unchecked exception, the JVM creates and
initializes an exception object. In contrast, when a program or library detects either a checked or unchecked exception, the
program/library code creates and initializes an exception object and uses the throw statement to pass that object to the JVM. The throw statement has the following syntax:
'throw' expression ';'
The throw statement begins with keyword throw, continues with an expression that evaluates to an object reference, and terminates with a semicolon character. expression's type must be Throwable or a subclass type. Otherwise, the compiler reports an error. The following code fragment demonstrates creating, initializing,
and throwing an exception object of type FileNotFoundException:
throw new FileNotFoundException ("Unable to open file " + filename); // Assume previous String filename; declaration.
throw to throw checked exception objects, as the previous code fragment demonstrates. In contrast, libraries often use throw to throw unchecked exception objects. Library methods throw unchecked exception objects because guaranteeing that a calling
method will always pass valid argument values to those methods proves impossible. For example, consider the following code
fragment:static void printReport (Employee e)
{
if (e == null)
throw new NullPointerException ();
// ... other code ...
}
The printReport(Employee e) library method checks Employee argument e's contents. If e contains a null reference, printReport(Employee e) creates and throws a NullPointerException unchecked exception object. Execution immediately leaves, and does not return to, the printReport(Employee e) method.
| Caution |
|---|
Do not attempt to throw objects from any class apart from Throwable or a Throwable subclass. Otherwise, the compiler reports an error. The compiler also reports an error when a method attempts to throw a
checked exception object but does not list that object's class name in the method's throws clause.
|
When a method throws a checked exception object, the compiler forces that method to list the object's class or superclass
in the method's throws clause. That clause appends to a method's signature and has the following syntax:
'throws' exceptionIdentifier1 ',' exceptionIdentifier2 ',' ...
The throws clause begins with keyword throws and continues with a comma-delimited list of exceptionIdentifier's. Each exceptionIdentifier identifies the class of a checked exception object directly (or indirectly, through a called method) thrown from the method.
The following code fragment illustrates a throws clause:
public static void main (String [] args) throws java.net.MalformedURLException
{
if (args.length < 1) return;
java.net.URL url = new java.net.URL (args [0]);
}
The above code fragment attempts to create an object from Java's URL class -- found in package java.net. If the contents of the String object, which args [0] references, do not represent a valid URL, the URL (String url) constructor throws a java.net.MalformedURLException object. Because that object represents a checked exception and because the main() method chooses not to receive that object, a throws clause must append to main()'s signature -- to inform the JVM that main() did not receive that object and that the JVM should begin searching for an appropriate exception handler with main()'s caller. (I explore URLs in a future article.)
| Tip |
|---|
To deal with failure that occurs inside a constructor, throw an exception object from that constructor. If the exception object
is checked, append a throws clause to the constructor signature. For example: class Employee { Employee () throws IOException { /* ... appropriate code ... */ } }. When a constructor throws an exception object, the JVM does not create an object from the constructor's class. Using the
previous example, if Employee() throws an IOException object, the JVM does not create an Employee object.
|
In "Object-Oriented Language Basics, Part 4," you learned about method overriding. In that article, you learned you must exactly specify a superclass method's name,
return type, and parameter list in a subclass when overriding the superclass method. Because a throws clause is part of a method's signature, when overriding a superclass method that has a throws clause, keep in mind two factors:
Free Download - 5 Minute Product Review. When slow equals Off: Manage the complexity of Web applications - Symphoniq
![]()
Free Download - 5 Minute Product Review. Realize the benefits of real user monitoring in less than an hour. - Symphoniq