Tuesday, December 15, 2009

Section 10.6. Creating and Throwing Your Own Exceptions










[Page 497 (continued)]

10.6. Creating and Throwing Your Own Exceptions


Like other Java classes, the Exception class can be extended to handle cases not already covered by Java's built-in exceptions. Exceptions that you define will be handled the same way by the Java interpreter, but you will have to tHRow them yourself.



[Page 498]

For example, Figure 10.20 shows the design of an exception that can be used for validating that an integer is less than or equal to a certain maximum value. It would be coded as follows:


 /**
* IntOutOfRangeException reports an exception when
* an integer exceeds its bound.
*/
public class IntOutOfRangeException extends Exception {

public IntOutOfRangeException (int Bound) {
super("The input value exceeds the bound " + Bound);
}
}




Figure 10.20. The IntOutOfRange exception.







The class extends Exception and consists entirely of a constructor method that calls the superclass constructor. The argument passed to the superclass constructor is the message that will be returned by getMessage() when an instance of this exception is created.


Now let's consider an example where this new exception will be thrown. Suppose we wish to constrain the IntField class that we developed previously (Fig. 10.14) so that it will only accept numbers less than a certain bound. First, let's modify IntField so that its bound can be set when an instance is created. We want its bound to be an instance variable with some initial value, and we want to provide a constructor that can be used to override the default (Fig. 10.21).




Figure 10.21. The revised IntField class contains a bound on the size of the numbers that should be entered.








[Page 499]

This leads to the following revision of IntField:


public class IntField extends JTextField {
private int bound = Integer.MAX_VALUE;

public IntField(int size, int max) {
super(size);
bound = max;
}
// The rest of the class is unchanged for now
} // IntField


Our new constructor has the signature IntField(int,int), which does not duplicate any of JTextField's constructors. This is good design, because in extending a class, we want to be careful about the effect our definitions have on the original methods in the superclass. Superclass methods should be overridden by design, not by accident. If a method is redefined inadvertently, it might not function as expected by users of the subclass.


Effective Design: Extending a Class

When extending a class, care must be taken to ensure that the superclass's methods are not inadvertently overridden. A superclass method should only be overridden by design, not by accident.



Note how we have handled the problem of setting the default value of the bound. Integer. MAX_VALUE is a class constant that sets the maximum value for the int type. It is an appropriate value to use, because any valid int that the user types should be less than or equal to MAX_VALUE. Given these changes to IntField, let's now incorporate our new exception into its getInt() method (Fig. 10.22).


Figure 10.22. The revised IntField class containing the revised getInt() method.





import javax.swing.*;

public class IntField extends JTextField {
private int bound = Integer.MAX_VALUE;

public IntField (int size) {
super(size);
}

public IntField(int size, int max) {
super(size);
bound = max;
}

public int getInt() throws NumberFormatException, IntOutOfRangeException {
int num = Integer.parseInt(getText());
if (num > bound)
throw new IntOutOfRangeException(bound);
return num;
} // getInt()
} // IntField





[Page 500]

This new version of getInt() tHRows an exception if the integer entered by the user is greater than the IntField's bound. Here again, it is difficult to handle this exception appropriately in this method. The method would either have to return an erroneous valuebecause it must return somethingor it must terminate. Neither is an acceptable alternative. It is far better to throw the exception to the calling method.


The IntFieldTester class (Fig. 10.23) has the design and functionality shown in Figure 10.15. It provides a simple GUI interface to test the IntField class. It prompts the user to type an integer less than 100, and then it echoes the user's input. Note how the exception is handled in the actionPerformed() method. If an exception is thrown in IntField.getInt(), the actionPerformed() method pops up an error dialog, and the erroneous input is not used. Instead, the user is given another chance to enter a valid integer.


Figure 10.23. An application that uses an IntField object to process integers.





import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class IntFieldTester extends JPanel implements ActionListener {
public static final int WIDTH = 300, HEIGHT = 300;
private JLabel prompt = new JLabel("Input an integer <= 100: ");
private IntField intField = new IntField(12, 100);
private int userInt;
private String message = "Hello";

public IntFieldTester() {
add(prompt);
intField.addActionListener(this);
add(intField);
setSize(WIDTH, HEIGHT);
} // IntFieldTester()

public void paintComponent( Graphics g ) {
g.setColor(getBackground()); // Clear the panel
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(getForeground());
g.drawString(message, 10, 70);
} // paintComponent()

public void actionPerformed(ActionEvent evt) {
try {
userInt = intField.getInt();
message = "You input " + userInt + " Thank you.";
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this,
"The input must be an integer. Please reenter.");
} catch (IntOutOfRangeException e) {
JOptionPane.showMessageDialog(this, e.getMessage());
} finally {
repaint();
}
} // actionPerformed()
public static void main(String args[]) {
JFrame f = new JFrame("IntField Tester");
IntFieldTester panel = new IntFieldTester();

[Page 501]
f.getContentPane().add(panel);
f.setSize(panel.WIDTH, panel.HEIGHT);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0); // Quit the application
}
});
} // main()
} // IntFieldTester class






Self-Study Exercises


Exercise 10.14

Define a new Exception named FieldIsEmptyException to be thrown if the user forgets to enter a value into a IntField.

Exercise 10.15

Modify the IntField.getInt() method so that it throws and catches the FieldIsEmptyException.













No comments: