Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
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.