Throwing Exceptions


Handling Exceptions

An exception object is “thrown” during the course of program execution to signal the occurrence of an exception condition. The object thrown will be of type Throwable and will either be an Error or RuntimeException (i.e. unchecked exception) or any other subtype of Exception. (i.e. checked exception) If you are writing code that might possibly throw a checked exception you must explicitly handle the thrown exception in some way. This section shows you how to use the try/catch/finally statement and its several authorized combinations to properly handle exceptions in your programs.

Try/Catch Statement

The try/catch statement, also referred to as a try/catch block, is used to properly handle an exception. The code that might throw the exception is placed in the try block and, if the exception is thrown, it is “caught” and handled in the catch block.

Let’s revisit example 15.1 and wrap the offending code in a try/catch block. Example 15.2 shows the modified code. The name of the class has been changed to TryCatchTestApp.

Example 15.2: TryCatchTestApp.java

image from book
 1     public class TryCatchTestApp { 2        public static void main(String[] args){ 3          try{ 4             int i = Integer.parseInt(args[0]); 5             System.out.println("The number entered was: " + i); 6          }catch(NumberFormatException e){ 7             System.out.println("The string you entered was not an integer!"); 8           } 9        } 10   }
image from book

There are several items to note in this version of the program. First, line 4 contains the code that may throw a NumberFormatException if the String object referred to at args[0] fails to parse to an integer value. Although NumberFormatException is a RuntimeException, and is therefore an unchecked exception, it’s still a good idea to catch exceptions of this type in your code.

Line 5 now contains the code that prints the value of the variable i to the console. Line 5 will only execute if line 4 successfully executes. In other words, if the NumberFormatException is thrown during the execution of line 4, the remaining lines of code in the try block will be skipped and program execution will jump to the code contained in the catch block. (If the exception thrown matches the exception type expected in the catch block.)

The catch block begins on line 6. The type of exception, in this case NumberFormatException, is used to declare a parameter for the catch clause named e. In this example the parameter e is not used inside the catch block, however, a diagnostic message is printed to the console informing the user that the string they entered was not an integer.

Figure 15-4 shows the results of running example 15.2.

image from book
Figure 15-4: Results of Running Example 15.2

Referring to figure 15-4 — The program appears to behave better now that the NumberFormatException is explicitly handled in a try/catch block. The program is run first with the string “5”, next with the string “789”, and a third time with the string “Some String” with expected results. However, if a user fails to enter a text string when running the program it will still throw the ArrayIndexOutOfBoundsException. We can fix this problem by adding another catch block to catch this type of exception.

Multiple Catch Blocks

It is often the case that your program runs the risk of throwing several different types of exceptions. More often than not you also want to provide some sort of custom error handling depending on the type of exception thrown. Multiple catch blocks can be used after a try block to handle this situation.

Example 15.3 gives an improved version of the previous example. The name of the class has been changed to MultipleCatchTestApp.

Example 15.3: MultipleCatchTestApp.java

image from book
 1     public class MultipleCatchTestApp { 2        public static void main(String[] args){ 3          try{ 4             int i = Integer.parseInt(args[0]); 5             System.out.println("The number entered was: " + i); 6          }catch(NumberFormatException e){ 7             System.out.println("The string you entered was not an integer!"); 8           } 9          catch(ArrayIndexOutOfBoundsException e){ 10            System.out.println("You must enter a string! -- Please try again!"); 11          } 12       } 13    }
image from book

Notice in this example that the second catch block was added just after the first catch block. The first catch block is skipped if its exception parameter type fails to match that of the thrown exception. In this case the thrown exception is then compared to the parameter type in the second catch block. If it’s a match the second catch block code is executed. If the thrown exception fails to match any of the expected exception types then the exception is propagated up the Java Virtual Machine calling stack in the hope that it will eventually find a block of code that will properly handle the exception. In this simple example there’s not much farther up the chain an exception can be deferred until the Java Virtual Machine handles it by printing its detail to the console.

The Importance Of Exception Type And Order In Multiple Catch Blocks

When using multiple catch blocks to catch different types of exceptions you must be aware of the types of exceptions you are trying to catch and the order in which they are caught.

The order in which you catch exceptions must go from the specific type to the general type. Since exceptions are objects that belong to a class hierarchy they behave like ordinary objects. This means that subclass objects can be substituted where base class objects are expected. For instance, if a catch clause parameter specifies an exception of type Exception then it will also catch and handle all subtypes of Exception. If you use multiple catch blocks and want to catch a subtype of Exception then the subtype (specific) catch block must appear before the base type (general) catch block.

Luckily, if you reverse the order and try to catch the general type of exception before the specific type the Java compiler will signal your error.

Example 15.4 shows how to catch a specific type of exception followed by a general type of exception.

Example 15.4: GoodCatchBlockOrderingTestApp.java

image from book
 1      public class GoodCatchBlockOrderingTestApp { 2       public static void main(String[] args){ 3           try{ 4              int i = Integer.parseInt(args[0]); 5              System.out.println("The number entered was: " + i); 6           }catch(NumberFormatException e){ 7              System.out.println("The string you entered was not an integer!"); 8            } 9           catch(Exception e){ 10             System.out.println("You must enter a string! -- Please try again!"); 11           } 12        } 13     }
image from book

This example looks like the previous example except the class name has been changed and the catch block on line 9 now catches Exception instead of ArrayIndexOutOfBoundsException. The behavior of this program is somewhat different because any Exception thrown from the try block, other than NumberFormatException, will be caught and handled in the second catch block.

You could achieve the same effect by substituting the class Throwable for the class Exception in the catch clause on line 9. In this way you would catch not only thrown Exceptions but Errors as well. (i.e. All Throwable objects!)

Generally speaking, you will want to catch and handle the most specific exception appropriate to your programming situation. If catching the general exception is good enough, so be it, however, finer levels of error handling are usually required to produce production-quality code.

Manipulating A Throwable Object

So far in this chapter I have only showed you how to print a simple diagnostic message to the console after an exception has been caught. In this section I want to show you what you can do with a Throwable object inside the catch block.

You can do several things with a Throwable object after it’s been caught. These actions are listed in the following bullets:

  • You could just rethrow the object but this is of limited value.

  • You can repackage (chain) the Throwable object and throw the new Throwable object. This is good to do if you want to hide low-level Exceptions from higher level programmatic abstractions.

  • You can perform some processing then rethrow the object.

  • You can display detail information about the Throwable object.

  • You can perform some processing and throw a new type of Throwable object.

  • You can perform a combination of these actions as required.

  • Or you can just catch and ignore the exception. (Not recommended for production code.)

Table 15-1 lists and summarizes several Throwable methods you will find immediately helpful. For a complete listing of Throwable methods consult the Java API documentation referenced at the end of this chapter.

Table 15-1: Helpful Throwable Methods

Method

Description

Throwable()

Default constructor.

Throwable(String message)

Constructor that lets you create a Throwable object with a message String.

Throwable(String message, Throwable cause)

Constructor that lets you create a Throwable object with both a message string and a Throwable cause object. The cause object allows Exception chaining in Java 1.4 and above.

Throwable(Throwable cause)

Constructor that lets you create a Throwable object with a Throwable cause object. The Throwable object’s message field will be set using cause.toString() or to null if the cause object is null.

void printStackTrace()

Prints the Throwable object’s stacktrace to the standard error stream. The standard error stream is the console by default.

String toString()

Returns a short description of the Throwable object.

String getMessage()

Returns the String object containing the message details of this Throwable object.

Throwable initCause(Throwable cause)

Initializes the cause field of the Throwable object.

Throwable getCause()

Returns the Throwable object referred to by the cause field.

The first four methods listed in table 15-1 are constructors. This means that there are four ways to create a Throwable object. You will see some of these constructor methods utilized in the Throwing Exceptions section later in this chapter.

You should also be aware that specific exception types may provide additional functionality appropriate to the type of exception being thrown. Exceptions of this type are usually found in the java.io and java.net packages. The best way to learn about the special behavior of the exceptions you are dealing with is to consult the Java Platform API documentation.

Example 15.5 expands on the previous example and shows you how to use several of the Throwable methods to extract detailed information about a caught exception.

Example 15.5: ExceptionDetailTestApp.java

image from book
 1     public class ExceptionDetailTestApp { 2      public static void main(String[] args){ 3          try{ 4             int i = Integer.parseInt(args[0]); 5             System.out.println("The number entered was: " + i); 6          }catch(NumberFormatException e){ 7             System.out.println("The string you entered was not an integer!"); 8             System.out.println(e.toString()); 9            // e.printStackTrace(); 10          } 11         catch(Exception e){ 12            System.out.println("You must enter a string! -- Please try again!"); 13            System.out.println(e.toString()); 14           // e.printStackTrace(); 15          } 16       } 17    }
image from book

This program is similar to example 15.4 with the exception of a class name change and the addition of four lines of code. On lines 8 and 9, located in the first catch block, the NumberFormatException parameter reference e is utilized to call the toString() and the printStackTrace() methods. (Line 9 is presently commented out.) The same is done on lines 13 and 14 of the second catch block. (Line 14 is presently commented out as well.)

Figure 15-5 shows the results of running this program.

image from book
Figure 15-5: Results of Running Example 15.5

Referring to figure 15-5 — the program is run with four different inputs: “4”, “456”, “x”, and null or no string. The level of exception detail provided by the toString() method is brief, as can be seen in the program output.

Let’s run a different version of this program to see the difference between the toString() and the printStackTrace() methods. Example 15.6 gives the modified code.

Example 15.6: ExceptionDetailTestApp.java (Mod 1)

image from book
 1     public class ExceptionDetailTestApp { 2     public static void main(String[] args){ 3         try{ 4            int i = Integer.parseInt(args[0]); 5            System.out.println("The number entered was: " + i); 6         }catch(NumberFormatException e){ 7            System.out.println("The string you entered was not an integer!"); 8            //System.out.println(e.toString()); 9            e.printStackTrace(); 10         } 11        catch(Exception e){ 12           System.out.println("You must enter a string! -- Please try again!"); 13           //System.out.println(e.toString()); 14           e.printStackTrace(); 15         } 16      } 17    }
image from book

The difference between this and the previous example is that lines 8 and 13 are now commented out. This will give us an example of the printStackTrace() method in action. Figure 15-6 shows the results of running this program. Compare figure 15-6 with figure 15-5 above and note the differences between calling the toString() and printStackTrace() methods. The printStackTrace() method gives more detail concerning the nature of the exception. If you don’t need this level of diagnostic output in your program use the toString() method.

image from book
Figure 15-6: Results of Running Example 15.6

Try/Catch/Finally Statement

A finally clause can be added to the try/catch statement to provide a means to guarantee the execution of a block of code in the event an exception occurs. Finally blocks are used when valuable computer resources must be freed up and released back to the operating system. This usually occurs when you are doing file I/O or network programming.

Example 15.7 expands on the previous example and demonstrates the use of a finally block.

Example 15.7: FinallyBlockTestApp.java

image from book
 1    public class FinallyBlockTestApp { 2     public static void main(String[] args){ 3         try{ 4            int i = Integer.parseInt(args[0]); 5            System.out.println("The number entered was: " + i); 6            if(i == 0){ 7              System.exit(0); 8            } 9         }catch(NumberFormatException e){ 10           System.out.println("The string you entered was not an integer!"); 11           //System.out.println(e.toString()); 12           e.printStackTrace(); 13         } 14        catch(Exception e){ 15           System.out.println("You must enter a string! -- Please try again!"); 16           //System.out.println(e.toString()); 17           e.printStackTrace(); 18         } 19        finally{ 20             System.out.println("The code in the finally block is guaranteed to execute!"); 21         } 22      } 23    }
image from book

Referring to example 15.7 — this program differs from the previous example in three ways: 1) the class name has been changed, 2) the finally block has been added starting on line 19, and 3) if the user enters a “0” on the command line when they run the program the if statement on line 6 will evaluate to true which will result in the System.exit() method being called on line 7. If one line of code in the try block is executed the code in the finally block is guaranteed to execute so long as the try block is not exited via a System.exit() method call. Figure 15-7 shows the results of running this program.

image from book
Figure 15-7: Results of Running Example 15.7

Referring to figure 15-7 — the program is run with several valid and invalid string inputs. Each time an exception is thrown the code in the finally block executes. However, when “0” is entered the execution of the Java Virtual Machine is stopped with a call to the System.exit() method.

Try/Finally Statement

As you saw earlier in this section the finally block can be omitted if one or more catch clauses follow a try block. Likewise, the catch clause can be omitted if a finally block is used in conjunction with a try block. However, with every try block you must use at least one catch clause or one finally clause as they both cannot be simultaneously omitted.

When can you use the try/finally block combination? Good question. Generally speaking you can use the try/ finally block combination anytime you want to guarantee a section of code will execute based upon the execution of some other section of code. Namely, if the code located in the try block executes then the code in the finally block is guaranteed to execute. So, in this regard, your imagination is the limit. However, in normal Java programming you don’t usually see try/finally blocks utilized in this fashion.

A more common use of the try/finally block would be in a situation where you intended not to catch a thrown exception (i.e. you will let if propagate up the calling stack) but if the exception is thrown you want to do some housekeeping nonetheless.

Quick Review

Code that might throw a checked exception must be contained in a try block unless the method in which it appears uses the throws clause to indicate it might throw the exception. (The use of the throws clause is covered in the next section.) Failure to properly handle a checked exception will result in a compiler error. Code that might throw an unchecked exception can optionally be contained in a try block. A try block must be accompanied by either one or more catch blocks, a finally block, or a combination of both.

The Throwable class provides some useful methods for getting information about the nature of an exception. Some exceptions provide additional information about themselves. This is especially true of exceptions belonging to the java.io and java.net packages. Consult the Java Platform API documentation for detailed information about specific exception types.




Java For Artists(c) The Art, Philosophy, and Science of Object-Oriented Programming
Java For Artists: The Art, Philosophy, And Science Of Object-Oriented Programming
ISBN: 1932504052
EAN: 2147483647
Year: 2007
Pages: 452

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net