All Java exception classes inherit, either directly or indirectly, from class Exception, forming an inheritance hierarchy. Programmers can extend this hierarchy to create their own exception classes.
Figure 13.3 shows a small portion of the inheritance hierarchy for class Throwable (a subclass of Object), which is the superclass of class Exception. Only Throwable objects can be used with the exception-handling mechanism. Class Throwable has two subclasses: Exception and Error. Class Exception and its subclassesfor instance, RuntimeException (package java.lang) and IOException (package java.io)represent exceptional situations that can occur in a Java program and that can be caught by the application. Class Error and its subclasses (e.g., OutOfMemoryError) represent abnormal situations that could happen in the JVM. Errors happen infrequently and should not be caught by applicationsit is usually not possible for applications to recover from Errors. [Note: The Java exception hierarchy is enormous, containing hundreds of classes. Information about Java's exception classes can be found throughout the Java API. The documentation for class Throwable can be found at java.sun.com/j2se/5.0/docs/api/java/lang/Throwable.html. From there, you can look at this class's subclasses to get more information about Java's Exceptions and Errors.]
Figure 13.3. Portion of class THRowable's inheritance hierarchy.
(This item is displayed on page 649 in the print version)
Java distinguishes between two categories of exceptions: checked exceptions and unchecked exceptions. This distinction is important, because the Java compiler enforces a catch-or-declare requirement for checked exceptions. An exception's type determines whether the exception is checked or unchecked. All exception types that are direct or indirect subclasses of class RuntimeException (package java.lang) are unchecked exceptions. This includes exceptions you have seen already, such as ArrayIndexOutOfBoundsExceptions and ArithmeticExceptions (shown in Fig. 13.3). All classes that inherit from class Exception but not class RuntimeException are considered to be checked exceptions. Classes that inherit from class Error are considered to be unchecked. The compiler checks each method call and method declaration to determine whether the method tHRows checked exceptions. If so, the compiler ensures that the checked exception is caught or is declared in a tHRows clause. Recall from Section 13.4 that the tHRows clause specifies the exceptions a method throws. Such exceptions are not caught in the method's body. To satisfy the catch part of the catch-or-declare requirement, the code that generates the exception must be wrapped in a TRy block and must provide a catch handler for the checked-exception type (or one of its superclass types). To satisfy the declare part of the catch-or-declare requirement, the method containing the code that generates the exception must provide a tHRows clause containing the checked-exception type after its parameter list and before its method body. If the catch-or-declare requirement is not satisfied, the compiler will issue an error message indicating that the exception must be caught or declared. This forces programmers to think about the problems that may occur when a method that throws checked exceptions is called. Exception classes are defined to be checked when they are consider important enough to catch or declare.
Software Engineering Observation 13.6
Programmers are forced to deal with checked exceptions. This results in more robust code than would be created if programmers were able to simply ignore the exceptions.
Common Programming Error 13.5
A compilation error occurs if a method explicitly attempts to throw a checked exception (or calls another method that throws a checked exception) and that exception is not listed in that method's tHRows clause.
Common Programming Error 13.6
If a subclass method overrides a superclass method, it is an error for the subclass method to list more exceptions in its tHRows clause than the overridden superclass method does. However, a subclass's throws clause can contain a subset of a superclass's throws list.
Software Engineering Observation 13.7
If your method calls other methods that explicitly throw checked exceptions, those exceptions must be caught or declared in your method. If an exception can be handled meaningfully in a method, the method should catch the exception rather than declare it.
Unlike checked exceptions, the Java compiler does not check the code to determine whether an unchecked exception is caught or declared. Unchecked exceptions typically can be prevented by proper coding. For example, the unchecked ArithmeticException thrown by method quotient (lines 913) in Fig. 13.2 can be avoided if the method ensures that the denominator is not zero before attempting to perform the division. Unchecked exceptions are not required to be listed in a method's throws clauseeven if they are, it is not required that such exceptions be caught by an application.
Software Engineering Observation 13.8
Although the compiler does not enforce the catch-or-declare requirement for unchecked exceptions, provide appropriate exception-handling code when it is known that such exceptions might occur. For example, a program should process the NumberFormatException from Integer method parseInt, even though NumberFormatException (a subclass of RuntimeException) is an unchecked exception type. This makes your programs more robust.
Various exception classes can be derived from a common superclass. If a catch handler is written to catch exception objects of a superclass type, it can also catch all objects of that class's subclasses. This enables a catch block to handle related errors with a concise notation and allows for polymorphic processing of related exceptions. One could certainly catch each subclass type individually if those exceptions required different processing. Of course, catching related exceptions in one catch block makes sense only if the handling behavior is the same for all subclasses.
If there are multiple catch blocks that match a particular exception type, only the first matching catch block executes when an exception of that type occurs. We stated earlier that it is a compilation error to catch the same type in two different catch blocks associated with a particular try block. This occurs when both types are exactly the same. However, there may be several catch blocks that match an exceptioni.e., several catch blocks whose types are the same as the exception type or a superclass of that type. For instance, we could follow a catch block for type ArithmeticException with a catch block for type Exceptionboth would match ArithmeticExceptions, but only the first matching catch block would execute.
Error-Prevention Tip 13.6
Catching subclass types individually is subject to error if you forget to test for one or more of the subclass types explicitly; catching the superclass guarantees that objects of all subclasses will be caught. Positioning a catch block for the superclass type after all other subclass catch blocks for subclasses of that superclass ensures that all subclass exceptions are eventually caught.
Common Programming Error 13.7
Placing a catch block for a superclass exception type before other catch blocks that catch subclass exception types prevents those blocks from executing, so a compilation error occurs.
Introduction to Computers, the Internet and the World Wide Web
Introduction to Java Applications
Introduction to Classes and Objects
Control Statements: Part I
Control Statements: Part 2
Methods: A Deeper Look
Classes and Objects: A Deeper Look
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
GUI Components: Part 1
Graphics and Java 2D™
Files and Streams
Searching and Sorting
Introduction to Java Applets
Multimedia: Applets and Applications
GUI Components: Part 2
Accessing Databases with JDBC
JavaServer Pages (JSP)
Strings, Characters and Regular Expressions
Appendix A. Operator Precedence Chart
Appendix B. ASCII Character Set
Appendix C. Keywords and Reserved Words
Appendix D. Primitive Types
Appendix E. (On CD) Number Systems
Appendix F. (On CD) Unicode®
Appendix G. Using the Java API Documentation
Appendix H. (On CD) Creating Documentation with javadoc
Appendix I. (On CD) Bit Manipulation
Appendix J. (On CD) ATM Case Study Code
Appendix K. (On CD) Labeled break and continue Statements
Appendix L. (On CD) UML 2: Additional Diagram Types
Appendix M. (On CD) Design Patterns
Appendix N. Using the Debugger
Inside Back Cover