When you write applets or applications using Java, sooner or later you're going to run into exceptions. An exception is a special type of error object that is created when something goes wrong in a program. After Java creates the exception object, it sends it to your program, an action called throwing an exception. It's up to your program to catch the exception. You do this by writing the exception-handling code. In this chapter, you get the inside info on these important error-handling objects.
In Chapter 28, "Communications," you got a quick look at exceptions and how they are handled in a program. Specifically, you had to be prepared to handle an exception when you created an URL object from a text string. This is because the text string may not use the proper syntax for an URL, making it impossible to create the URL object. In this case, the URL constructor throws an exception object called MalformedURLException. Listing 30.1 shows the code segment that handles this exception.
Listing 30.1 LST30_1.TXT: Handling an Exception.
try { URL url = new URL(str); AppletContext context = getAppletContext(); context.showDocument(url); } catch (MalformedURLException e) { badURL = true; repaint(); }
As you can see from the listing, you place the code that may cause the exception in a try program block, whereas the exception-handling code goes into a catch program block. In this case, the first line of the try block attempts to create an URL object from the string given in the variable str. If the string is not properly formatted for an URL, the URL constructor throws a MalformedURLException. When this happens, Java ignores the rest of the code in the try block and jumps to the catch block, where the program handles the exception. On the other hand, if the URL object gets created okay, Java executes all the code in the try block and skips the catch block.
NOTE |
The catch program block does more than direct program execution. It actually catches the exception object thrown by Java. For example, in Listing 30.1, you can see the exception object being caught inside the parentheses following the catch keyword. This is very similar to a parameter being received by a method. In this case, the type of the "parameter" is MalformedURLException and the name of the parameter is e. If you need to, you can access the exception object's methods through the e object. |
Java defines many exception objects that may be thrown by the methods in Java's classes. How do you know which exceptions you have to handle? First, if you write an applet that calls a method that may throw an exception, Java insists that you handle the exception in one way or another. If you fail to do so, your applet will not compile. Instead, you'll receive an error message indicating where your program may generate the exception (see Figure 30.1).
Although the compiler's error messages are a clue that something is amiss, the clever programmer will look up a method in Java's documentation before using the method. Then, the programmer will know in advance whether that method requires exception-handling code. If you're interested in seeing the exceptions that are defined by a package, find the package's section in Java's online documentation (see Figure 30.2), where the classes and exceptions are listed.
The online documentation also lists all the methods that comprise a particular package. By looking up the method in the documentation (see Figure 30.3), you can see what types of arguments the method expects, the type of value the method returns, and whether the method may throw an exception. If the method shows that it can throw an exception, your code must handle the right type of exception or the program will not compile.
Figure 30.3 : The online documentation for a method shows the exception the method may throw.
One handy thing about exceptions is that you don't have to handle them in the same method in which the exception is generated. For example, in Listing 30.1, the applet tries to create an URL object. If the URL creation fails, the URL constructor throws an exception that the event() method handles in its catch block. But what if, for some reason, you don't want to handle the exception in the same method in which you call the URL constructor? You can simply pass the buck, so to speak, by throwing the exception on up the method hierarchy. Listing 30.2 shows one way you might do this with the MalformedURLException exception.
Listing 30.2 LST30_2.TXT: Throwing an Exception.
public boolean action(Event evt, Object arg) { try GetURL(); catch (MalformedURLException e) { badURL = true; repaint(); } return true; } protected void GetURL() throws MalformedURLException { String str = textField.getText(); URL url = new URL(str); AppletContext context = getAppletContext(); context.showDocument(url); }
In this listing, the call to the URL class's constructor has been moved to a method called GetURL(). However, GetURL() does not directly handle the MalformedURLException exception. Instead, it passes the exception back to the action() method. Java knows that GetURL() wants to pass the exception, because GetURL() adds the phrase throws MalformedURLException to its signature. Throwing the exception, however, doesn't relieve you from handling it eventually. Notice that in Listing 30.2, the exception still gets handled in the action() method.
In short, you can handle an exception in two ways. The first way is to write try and catch program blocks exactly where you call the function that may generate the exception. The second way is to declare the method as throwing the exception, in which case you must write the try and catch program blocks in the method that calls the "throwing" method, as shown in Listing 30.2.
Java defines many different exception objects. Some of these you must always handle in your code if you call a function that may throw the exception. Others are generated by the system when something like memory allocation fails, an expression tries to divide by zero, a null value is used inappropriately, and so on. You can choose to watch for this second kind of exception or let Java deal with them.
Just as with programming before exceptions existed, you should
always be on the lookout for places in your program where an exception
could be generated. These places are usually associated with user
input, which can be infamously unpredictable. However, programmers,
too, have been known to make mistakes in their programs that lead
to exception throwing. Some common exceptions you may want to
watch out for at appropriate places in your applet are listed
in Table 30.1.
Exceptions | Description |
ArithmeticException | Caused by math errors such as division by zero |
ArrayIndexOutOfBounds Exception | Caused by bad array indexes |
ArrayStoreException | Caused when a program tries to store the wrong type of data in an array |
FileNotFoundException | Caused by an attempt to access a nonexistent file |
IOException | Caused by general I/O failures, such as inability to read from a file |
NullPointerException | Caused by referencing a null object |
NumberFormatException | Caused when a conversion between strings and numbers fails |
OutOfMemoryException | Caused when there's not enough memory to allocate a new object |
SecurityException | Caused when an applet tries to perform an action not allowed by the browser's security setting |
StackOverflowException | Caused when the system runs out of stack space |
StringIndexOutOfBounds Exception | Caused when a program attempts to access a nonexistent characterposition in a string |
TIP |
You can catch all types of exceptions by setting up your catch block for exceptions of type Exception, like this: catch (Exception e). Call the exception's getMessage() method (inherited from the Throwable superclass) to get information about the specific exception that you've intercepted. |
Experienced programmers usually know when their code may generate an exception of some sort. However, when you first start writing applets with exception-handling code, you may not be sure what type of exceptions to watch out for. One way to discover this information is to see what exceptions get generated as you test your applet. Listing 30.3, for example, is an applet called ExceptionApplet that divides two integer numbers obtained from the user and displays the integer result (dropping any remainder). Because the applet must deal with user input, the probability of disaster is high. ExceptionApplet, however, contains no exception-handling code.
Listing 30.3 ExceptionApplet.java: An Applet with No Exception Handling.
import java.awt.*; import java.applet.*; public class ExceptionApplet extends Applet { TextField textField1, textField2; String answerStr; public void init() { textField1 = new TextField(15); add(textField1); textField2 = new TextField(15); add(textField2); answerStr = "Undefined"; } public void paint(Graphics g) { Font font = new Font("TimesRoman", Font.PLAIN, 24); g.setFont(font); int answer = int1 / int2; answerStr = String.valueOf(answer); repaint(); return true; } }
You'll use this applet as the starting point for a more robust applet. When you run the applet using Appletviewer, you'll see the window shown in Figure 30.4. Enter a number into each of the two text boxes and then press Enter. The program then divides the first number by the second number and displays the result (see Figure 30.5).
Figure 30.4 : This is ExceptionApplet running under Appletviewer.
Figure 30.5 : ExceptionApplet divides the first number by the second.
As long as the user enters valid numbers into the text boxes, the program runs perfectly. What happens, though, if the user presses Enter when either or both of the text boxes are empty? Java immediately throws a NumberFormatException when the action() method attempts to convert the contents of the text boxes to integer values. You can see this happening by watching the DOS window from which you ran Appletviewer, as shown in Figure 30.6. As you can see in the figure, Java has displayed quite a few lines that trace the exception. The first line (the one that starts with the word exception) tells you the type of exception you've encountered.
Figure 30.6 : Here, Java reports a NumberFormat
You now know that the user can cause a NumberFormatException if he or she leaves one or more text boxes blank or enters an invalid numerical value, like the string one. In order to ensure that your applet will not be caught by surprise, you now need to write the code that will handle this exception. Follow these steps to add this new code:
Listing 30.4 LST30_4.TXT: Handling the NumberFormatException Exception.
public boolean action(Event evt, Object arg) { String str1 = textField1.getText(); String str2 = textField2.getText(); try { int int1 = Integer.parseInt(str1); int int2 = Integer.parseInt(str2); int answer = int1 / int2; answerStr = String.valueOf(answer); } catch (NumberFormatException e) { answerStr = "Bad number!"; } repaint(); return true; }
In Listing 30.4, the action() method now uses try and catch program blocks to handle the NumberFormatException gracefully. Figure 30.7 shows what happens now when the user leaves the text boxes blank. When the program gets to the first call to String.valueOf(), Java generates the NumberFormatException exception, which causes program execution to jump to the catch block. In the catch block, the program sets the display string to Bad number! The call to repaint() ensures that this message to the user gets displayed on the screen.
Figure 30.7 : ExceptionApplet2 handles the NumberFormat
So, here you are, having a good time entering numbers into ExceptionApplet2's text boxes and getting the results. Without thinking, you enter a zero into the second box, Java tries to divide the first number by the zero, and pow!- you've got yourself an ArithmeticException exception. What to do? You're already using your catch block to grab NumberFormatException; now, you've got yet another exception to deal with.
The good news is that you're not limited to only a single catch block. You can, in fact, create catch blocks for any exceptions you think the program may generate. To see how this works with your new applet, follow these steps:
Listing 30.5 LST30_5.TXT: Handling Multiple Exceptions.
public boolean action(Event evt, Object arg) { String str1 = textField1.getText(); String str2 = textField2.getText(); try { int int1 = Integer.parseInt(str1); int int2 = Integer.parseInt(str2); int answer = int1 / int2; answerStr = String.valueOf(answer); } catch (NumberFormatException e) { answerStr = "Bad number!"; } catch (ArithmeticException e) { answerStr = "Division by 0!"; } repaint(); return true; }
If you examine Listing 30.5, you'll see that the action() method now defines two catch program blocks, one each for the NumberFormatException and ArithmeticException exceptions. In this way, the program can watch for both potential problems from within a single try block. If you discovered another exception that your program may cause, you can add yet another catch block.
NOTE |
Although handling exceptions is a powerful tool for creating crash-proof programs, you should use them only in situations where you have little control over the cause of the exception, such as when dealing with user input. If your applet causes an exception because of a program bug, you should track down and fix the problem rather than try to catch the exception. |
TIP |
There may be times when you want to be sure that a specific block of code gets executed whether or not an exception is generated. You can do this by adding a finally program block after the last catch. The code in the finally block gets executed after the try block or catch block finishes its thing. |
A good applet doesn't give the user nasty surprises. It's up to the programmer to check for potential problem spots in programs and guard against program failure. One tool the programmer can use is exceptions, which are objects created by Java when a program encounters a serious error. After Java creates an exception object, it throws the exception and expects some other part of the program to catch the exception.
The try and catch program blocks enable you to test for exceptions and respond to them as appropriate. Some types of exceptions must be handled in your program before the Java compiler will compile the program. Other exceptions-those that may be generated at runtime by more unpredictable problems like referencing a null pointer or dividing by zero-don't have to be handled in your program. However, a good programmer will design his or her applet so that common exceptions are handled where appropriate.
Figure 30.9 : This is ExceptionApplet5 running under Appletviewer.