The Essence of OOP using Java, Exception Handling
You have a choice
Therefore, when writing exception handlers, you have a choice. You can write a handler whose exception type corresponds to a node in the inheritance hierarchy, and it will be appropriate to catch exceptions of that type, or any subclass of that type.
Alternately, you can write a handler whose exception type corresponds to a leaf, in which case, it will be appropriate to catch exceptions of that type only.
And finally, you can mix and match, writing some exception handlers whose type corresponds to a node, and other exception handlers whose type corresponds to a leaf. In all cases, however, be sure to position your exception handlers in reverse subclass order, with the furthermost subclass from the root appearing first, and the root class appearing last.
The finally block
And finally (no pun intended), Campione and Walrath tell us:
"Java's finally block provides a mechanism that allows your method to clean up after itself regardless of what happens within the try block. Use the finally block to close files or release other system resources."
To elaborate, the finally block can be used to provide a mechanism for cleaning up open files, etc., before allowing control to be passed to a different part of the program. You accomplish this by writing the cleanup code within a finally block.
Code in finally block is always executed
It is important to remember that the runtime system always executes the code within the finally block regardless of what happens within the try block.
If no exceptions are thrown, none of the code in catch blocks is executed, but the code in the finally block is executed.
If an exception is thrown and the code in an exception handler is executed, once the execution of that code is complete, control is passed to the finally block and the code in the finally block is executed.
(There is one important exception to the above. If the code in the catch block terminates the program by executing System.exit(0), the code in the finally block will not be executed.)
The power of the finally block
The sample program shown in Listing 5 illustrates the power of the finally
block.
/*File Excep15.java Copyright 2002, R. G. Baldwin Tested with JDK 1.4.0 under Win2000 **************************************/ class Excep15{ public static void main( String[] args){ new Excep15().aMethod(); }//end main //---------------------------------// void aMethod(){ try{ int x = 5/0; }//end try block catch(ArithmeticException e){ System.out.println( "In catch, terminating aMethod"); return; }//end catch block finally{ System.out.println( "Executing finally block"); }//end finally block System.out.println( "Out of catch block"); }//end aMethod }//end class Excep15 Listing 5 |
Execute return statement in catch block
The code in Listing 5 forces an ArithmeticException by attempting to do an integer divide by zero. Control is immediately transferred to the matching catch block, which prints a message and then executes a return statement.
Normally, execution of a return statement terminates the method immediately. In this case, however, before the method terminates and returns control to the calling method, the code in the finally block is executed. Then control is transferred to the main method, which called this method in the first place.
Figure 8 shows the output produced by this program.
In catch, terminating aMethod Executing finally block Figure 8 |
This program demonstrates that the finally block really does have the final word.
Declaring exceptions thrown by a method
Sometimes it is better to handle exceptions in the method in which they are detected, and sometimes it is better to pass them up the call stack and let another method handle them.
In order to pass exceptions up the call stack, you must declare them in your method signature.
To declare that a method throws one or more exceptions, you add a throws clause to the method signature for the method. The throws clause is composed of the throws keyword followed by a comma-separated list of all the exceptions thrown by that method.
The throws clause goes after the method name and argument list and before the curly bracket that defines the scope of the method.
Figure 9 shows the syntax for declaring that a method throws four
different types of exceptions.
void myMethod() throws InterruptedException, MyException, HerException, UrException { //method code }//end myMethod() Figure 9 |
Assuming that these are checked exceptions, any method calling this method would be required to either handle these exception types, or continue passing them up the call stack. Eventually, some method must handle them or the program won't compile.
(Note however that while it might not represent good programming practice, it is allowable to declare that the main method throws exceptions. This is a way to avoid handling checked exceptions and still get your program to compile.)
The throw keyword
Before your code can catch an exception, some Java code must throw one. The exception can be thrown by code that you write, or by code that you are using that was written by someone else.
Regardless of who wrote the code that throws the exception, it's always thrown with the Java throw keyword. At least that is true for exceptions that are thrown by code written in the Java language.
(Exceptions such as ArithmeticException are also thrown by the runtime system, which is probably not written using Java source code.)
A single argument is required
When formed into a statement, the throw keyword requires a single
argument, which must be a reference to an object instantiated from the
Throwable class, or any subclass of the Throwable class. Figure
10 shows an example of such a statement.
throw new myThrowableClass("Message"); Figure 10 |
If you attempt to throw an object that is not instantiated from Throwable or one of its subclasses, the compiler will refuse to compile your program.
Defining your own exception classes
Now you know how to write exception handlers for those exception objects that are thrown by the runtime system, and thrown by methods in the standard class library.
It is also possible for you to define your own exception classes, and to cause objects of those classes to be thrown whenever an exception occurs. In this case, you get to decide just what constitutes an exceptional condition.
For example, you could write a data-processing application that processes integer data obtained via a TCP/IP link from another computer. If the specification for the program indicates that the integer value 10 should never be received, you could use an occurrence of the integer value 10 to cause an exception object of your own design to be thrown.
Choosing the exception type to throw
Before throwing an exception, you must decide on its type. Basically, you have two choices in this regard:
- Use an exception class written by someone else, such as the myriad of exception classes defined in the Java standard library.
- Define an exception class of your own.
An important question
So, an important question is, when should you define your own exception classes and when should you use classes that are already available. Because this is only one of many design issues, I'm not going to try to give you a ready answer to the question. However, I will refer you to The Java Tutorial by Campione and Walrath where you will find a checklist to help you make this decision.
Choosing a superclass to extend
If you decide to define your own exception class, it must be a subclass of Throwable. You must decide which class you will extend.
The two existing subclasses of Throwable are Exception and Error. Given the earlier description of Error and its subclasses, it is not likely that your exceptions would fit the Error category. (In concept, errors are reserved for serious hard errors that occur deep within the system.)
Checked or unchecked exception
Therefore, your new class should probably be a subclass of Exception. If you make it a subclass of RuntimeException, it won't be a checked exception. If you make it a subclass of Exception, but not a subclass of RuntimeException, it will be a checked exception.
Only you can decide how far down the Exception hierarchy you want to go before creating a new branch of exception classes that are unique to your application.
Naming conventions
Many Java programmers append the word Exception to the end of all class names that are subclasses of Exception, and append the word Error to the end of all class names that are subclasses of Error.
One more sample program
Let's wrap up this lesson with one more sample program named Excep16. We will define our own exception class in this program. Then we will throw, catch and process an exception object instantiated from that class.
Discuss in fragments
This program is a little longer than the previous programs, so I will break it down and discuss it in fragments. A complete listing of the program is shown in Listing 10.
The class definition shown in Listing 6 is used to construct a custom
exception object that encapsulates a message. Note that this class extends
Exception. (Therefore, it is a checked exception.)
class MyException extends Exception{ MyException(String message){//constr super(message); }//end constructor }//end MyException class Listing 6 |
The constructor for this class receives an incoming String message parameter and passes it to the constructor for the superclass. This makes the message available for access by the getMessage method invoked in the catch block.
The try block
Listing 7 shows the beginning of the main method, including the entire
try block
class Excep16{//controlling class public static void main( String[] args){ try{ for(int cnt = 0; cnt < 5; cnt++){ //Throw a custom exception, and // pass message when cnt == 3 if(cnt == 3) throw new MyException("3"); //Transfer control before // processing for cnt == 3 System.out.println( "Processing data for cnt = " + cnt); }//end for-loop }//end try block Listing 7 |
The main method executes a for loop (inside the try block) that guarantees that the variable named cnt will reach a value of 3 after a couple of iterations.
Once during each iteration, (until the value of cnt reaches 3)
a print statement inside the for loop displays the value of cnt.
This results in the output shown in Figure 11.
Processing data for cnt = 0 Processing data for cnt = 1 Processing data for cnt = 2 Figure 11 |
What happens when cnt equals 3?
However, when the value of cnt equals 3, the throw statement highlighted in boldface in Listing 7 is executed. This causes control to transfer immediately to the matching catch block following the try block (see Listing 8). During this iteration, the print statement following the throw statement is not executed. Therefore, the output never shows a value for cnt greater than 2, as shown in Figure 11.
The catch block
Listing 8 shows a catch block whose type matches the type of exception
thrown in Listing 7.
catch(MyException e){ System.out.println( "In exception handler, " + "get the message\n" + e.getMessage()); }//end catch block Listing 8 |
When the throw statement is executed in Listing 7, control is transferred immediately to the catch block in Listing 8. No further code is executed within the try block.
A reference to the object instantiated as the argument to the throw keyword in Listing 7 is passed as a parameter to the catch block. That reference is known locally by the name e inside the catch block.
Using the incoming parameter
The code in the catch block invokes the method named getMessage
(inherited from the Throwable class) on the incoming parameter and
displays that message on the screen. This produces the output shown in
Figure 12.
In exception handler, get the message 3 Figure 12 |
When the catch block finishes execution ...
When the code in the catch block has completed execution, control is
transferred to the first executable statement following the catch block
as shown in Listing 9.
System.out.println( "Out of catch block"); }//end main }//end class Excep16 Listing 9 |
That executable statement is a print statement that produces the output shown
in Figure 13.
Out of catch block Figure 13 |
A complete listing of the program is shown in Listing 10.
/*File Excep16.java Copyright 2002, R. G. Baldwin Illustrates defining, throwing, catching, and processing a custom exception object that contains a message. Tested using JDK 1.4.0 under Win 2000 The output is: Processing data for cnt = 0 Processing data for cnt = 1 Processing data for cnt = 2 In exception handler, get the message 3 Out of catch block **************************************/ //The following class is used to // construct a customized exception // object containing a message class MyException extends Exception{ MyException(String message){//constr super(message); }//end constructor }//end MyException class //===================================// class Excep16{//controlling class public static void main( String[] args){ try{ for(int cnt = 0; cnt < 5; cnt++){ //Throw a custom exception, and // pass message when cnt == 3 if(cnt == 3) throw new MyException("3"); //Transfer control before // processing for cnt == 3 System.out.println( "Processing data for cnt = " + cnt); }//end for-loop }//end try block catch(MyException e){ System.out.println( "In exception handler, " + "get the message\n" + e.getMessage()); }//end catch block //-------------------------------// System.out.println( "Out of catch block"); }//end main Listing 10 |
Summary
This lesson has covered many of the details having to do with exception handling in Java. By now, you should know that the use of exception handling is not optional in Java, and you should have a pretty good idea how to use exception handling in a beneficial way.
Along the way, the discussion has included the following topics:
- What is an exception?
- How do you throw and catch exceptions?
- What do you do with an exception once you have caught it?
- How do you make use of the exception class hierarchy provided by the Java development environment?
What's Next?
For the time being, that completes the miniseries entitled "The Essence of
OOP using Java." I may decide to come back later and add some lessons
on inner classes and other similar topics, but it will probably be a while
before I get around to that. In the meantime, I sincerely hope that you
have enjoyed this miniseries, and have found the lessons useful in your
continuing effort to learn and understand OOP as implemented using Java.
Copyright 2002, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
About the author
Richard Baldwin is a college professor (at Austin Community College in Austin, Texas) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.
Richard has participated in numerous consulting projects, and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
-end-
Page 3 of 3
This article was originally published on September 3, 2002