Chapter 30

Exceptions


CONTENTS

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.

Java's Exceptions

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).

Figure 30.1 : Java's compiler gives you an error message if you fail to handle an exception in your applet.

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.

Figure 30.2 : Java's online documentation lists the exception objects that may be thrown by methods in a class.

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.

Throwing an Exception

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.

Types of Exceptions

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.

Table 30.1  Common Java Exceptions.

ExceptionsDescription
ArithmeticExceptionCaused by math errors such as division by zero
ArrayIndexOutOfBounds Exception Caused by bad array indexes
ArrayStoreExceptionCaused when a program tries to store the wrong type of data in an array
FileNotFoundExceptionCaused by an attempt to access a nonexistent file
IOExceptionCaused by general I/O failures, such as inability to read from a file
NullPointerExceptionCaused by referencing a null object
NumberFormatExceptionCaused when a conversion between strings and numbers fails
OutOfMemoryExceptionCaused when there's not enough memory to allocate a new object
SecurityExceptionCaused when an applet tries to perform an action not allowed by the browser's security setting
StackOverflowExceptionCaused 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.

Determining the Exceptions to Handle

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 NumberFormatException exception.

Example: Catching a Runtime Exception

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:

  1. Load ExceptionApplet into your text editor.
  2. Replace the action() method with the new version shown in Listing 30.4.
  3. In the class declaration line, change the name of the class to ExceptionApplet2.
  4. Save the new applet under the name ExceptionApplet2.java.
  5. Load the EXCEPTIONAPPLET.htmL file.
  6. Change all occurrences of ExceptionApplet to ExceptionApplet2.
  7. Save the file as EXCEPTIONAPPLET2.htmL.

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 NumberFormatException exception gracefully.

Example: Handling Multiple Exceptions

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:

  1. Load ExceptionApplet2 into your text editor.
  2. Replace the action() method with the new version shown in Listing 30.5.
  3. In the class declaration line, change the name of the class to ExceptionApplet3.
  4. Save the new applet under the name ExceptionApplet3.java.
  5. Load the EXCEPTIONAPPLET.htmL file.
  6. Change all occurrences of ExceptionApplet to ExceptionApplet3.
  7. Save the file as EXCEPTIONAPPLET3.htmL.

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.

Summary

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.

Review Questions

  1. How do you use a try program block?
  2. How do you use a catch program block?
  3. Do you have to catch all types of exceptions that might be thrown by Java?
  4. When a method you call is defined as potentially throwing an exception, do you have to handle that exception in your program?
  5. How many exceptions can you associate with a single try block?
  6. How do you pass an exception up from a called method to the calling method?
  7. What are the two main types of exceptions that Java may throw?

Review Exercises

  1. Write an applet that creates a button object. Set up exception-handling code for the OutOfMemoryException exception that could possibly occur when Java tries to allocate resources for the button.
  2. Write an applet that catches all Exception objects and displays the string returned by the Exception object's getMessage() method. (Not all Exception objects return message strings. Test your program by generating a divide-by-zero error, which will cause Java to throw an ArithmeticException exception. This exception does generate a message string.) You can find the solution to this exercise in the CHAP30 folder of this book's CD-ROM. The applet is called ExceptionApplet4. Figure 30.8 shows what the applet looks like while running under Appletviewer.
    Figure 30.8 : ExceptionApplet4 displays the message string returned by an Exception object's getMessage() method.

  3. Write an applet that enables the user to enter values into an array. Use two TextField objects, the first being where the user shouldenter the index at which to place the value, and the second being the value to add to the array. Set up the applet so that it responds to ArrayIndexOutOfBoundsException and NumberFormatException exceptions. You can find the solution to this exercise in the CHAP30 folder of this book's CD-ROM. The applet is called ExceptionApplet5. Figure 30.9 shows what the applet looks like while running under Appletviewer.

    Figure 30.9 : This is ExceptionApplet5 running under Appletviewer.