10: More GUI Topics and Exceptions

What We Will Cover


Illuminations

Questions on Assignments?

  • Nothing

Questions from last class?

10.1: Using Labels and Text Fields

Objectives

At the end of the lesson the student will be able to:

  • Use JLabels to display text
  • Use text fields for entering data

10.1.1: Using Labels

  • A JLabel is typically used to display text in a GUI
  • These labels often display text for other components
  • For instance, you may want a label for a text field

Code to Add Labels

  • Following code adds a label to a panel
  • JLabel label = new JLabel("Label text");
    JPanel panel = new JPanel();
    panel.add(label);
    
  • Other constructors of a JLabel allow Icons as well

Some Commonly-Used Constructors and Methods from JLabel

Constructor/Method Description
JLabel() Creates a blank label.
JLabel(Icon) Creates a label with the specified image.
JLabel(String) Creates a label with the specified text.
setIcon(Icon) Sets the icon for a label.
setHorizontalAlignment(int) Sets the alignment along the 10 axis, Usually JLabel.LEFT, JLabel.CENTER,or JLabel.RIGHT.
setText(String) Sets the text for a label.

For Example

  • In the following, we use this image for an icon: A pretty but meaningless splat (From the Java Tutorial)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class LabelApp extends JFrame {
    public final static int X_LOC = 100, Y_LOC = 100,
                            WIDTH = 150, HEIGHT = 125;

    public LabelApp() {
        super("Label Application");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        ImageIcon icon = new ImageIcon("icon.gif",
            "A pretty but meaningless icon");
        JLabel label1 = new JLabel("Text-only label");
        JLabel label2 =
            new JLabel("Image and text label");
        label2.setIcon(icon);
        label2.setHorizontalAlignment(JLabel.CENTER);
        JLabel label3 = new JLabel(icon);

        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(label1, BorderLayout.NORTH);
        panel.add(label2, BorderLayout.CENTER);
        panel.add(label3, BorderLayout.SOUTH);

        Container contentPane = getContentPane();
        contentPane.add(panel);

        setBounds(X_LOC, Y_LOC, WIDTH, HEIGHT);
        setVisible(true);
    }

    public static void main(String[] args) {
        new LabelApp();
    }
}

Further Information

10.1.2: Displaying Images on JLabels

  • An easy way to display images is to use an ImageIcon object with a JLabel
  • ImageIcons can be created from either files or URLs
  • ImageIcon myImage = new ImageIcon("image.jpg");
    
  • Note that Java only supports GIF, JPEG and PNG images
    • If you have images in other formats, you will need to convert them
  • We use the ImageIcon to instantiate a JLabel
  • JLabel label = new JLabel(myImage);
    
  • We then add the JLabel to the application in the usual way

Example: Displaying an Image

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

public class ImageDisplayer extends JFrame {
    public final static int X_LOC = 100, Y_LOC = 100,
                            WIDTH = 300, HEIGHT = 400;

    public ImageDisplayer() {
        super("Image Display Application");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        ImageIcon myImage = new ImageIcon("image.jpg");
        JLabel label = new JLabel(myImage);
        Container contentPane = getContentPane();
        contentPane.add(label);

        setBounds(X_LOC, Y_LOC, WIDTH, HEIGHT);
        setVisible(true);
    }

    public static void main(String[] args) {
        new ImageDisplayer();
    }
}

We can download an image from my homepage and save it as image.jpg.

10.1.3: Using Text and Password Fields

  • JTextField: single-line area in which user can enter text
  • JPasswordField: extends JTextField and hides characters that a user enters
  • When the user presses the Enter key inside a JTextField, the component generates an ActionEvent
  • Thus, you can use an ActionListener to listen for text actions
  • Alternatively, you can add buttons to perform actions

Code for Text Fields

  • Code to declare a JTextField and a JPasswordField
  • JTextField login = new JTextField(10);
    JPasswordField password = new JPasswordField("asecret");
    
  • Code to register the handlers
  • login.addActionListener(this);
    password.addActionListener(this);
    
  • Example code that works with text and password fields
  • String data = login.getText();
    String pass = password.getPassword();
    password.setText("asecret");
    login.setEditable(false);
    

Commonly-Used Constructors and Methods from JTextField

Constructor/Method Description
JTextField(int) Creates an empty text field with the specified number of columns.
JTextField(String, int) Creates a text field that starts with the text and contains the number of columns.
getText() Returns the text contained in the text field as a String object.
setText() Sets the text field to the specified String.
setColumns(int) Sets the number of columns for the text field.
setEditable(boolean) Sets whether this text field is editable or not.

Commonly-Used Constructors and Methods from JPasswordField

Constructor/Method Description
JPasswordField(int) Creates an empty text field with the specified number of columns.
JTextField(String, int) Creates a password field that starts with the text and contains the number of columns.
getPassword() Returns the text stored in the component as a char[].

For Example

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

public class LoginDemo extends JFrame
        implements ActionListener {

    private JTextField login;
    private JPasswordField password;
    private JButton loginButton;

    public LoginDemo() {
        super("Login Application");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        JLabel loginLabel = new JLabel("User name:");
        login = new JTextField(10);
        JPanel loginPanel = new JPanel();
        loginPanel.add(loginLabel);
        loginPanel.add(login);

        JLabel pwdLabel = new JLabel("Password:");
        password = new JPasswordField("asecret", 10);
        JPanel pwdPanel = new JPanel();
        pwdPanel.add(pwdLabel);
        pwdPanel.add(password);

        loginButton = new JButton("Press to Login");

        Container contentPane = getContentPane();
        contentPane.add(loginPanel, BorderLayout.NORTH);
        contentPane.add(pwdPanel, BorderLayout.CENTER);
        contentPane.add(loginButton, BorderLayout.SOUTH);

        login.addActionListener(this);
        password.addActionListener(this);
        loginButton.addActionListener(this);

        pack();
        setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == login) {
            password.requestFocus();
        } else if (e.getSource() == password) {
            checkLogin();
            login.requestFocus();
        } else if (e.getSource() == loginButton) {
            checkLogin();
            login.requestFocus();
        }
    }

    public void checkLogin() {
        JOptionPane.showMessageDialog(null,
            "Login: " + login.getText()
            + "\nPassword: "
            + new String(password.getPassword()),
            "Login Message",
            JOptionPane.INFORMATION_MESSAGE);
    }

    public static void main(String[] args) {
        new LoginDemo();
    }
}
  • Note how the loginLabel and login text field are grouped into a JPanel
  • The pwdLabel and password field are grouped similarly
  • This keeps these components grouped together during frame resizing

10.1.4: Summary

  • A JLabel is commonly used to display text or images in a GUI
  • An image is loaded using an ImageIcon
  • A JTextField provides a single line area for users to type information
  • A JPasswordField extends JTextField and hides characters that a user enters
  • Grouping labels and text fields keeps associated components together during resizing

Exercise 10.1

Take one minute to prepare answers to the following questions:

  1. How is the text set for a label?
  2. How can the text be retrieved from a text field?
  3. How can text in a text field be changed?

10.2: Exception Handling Basics

Objectives

At the end of the lesson the student will be able to:

  • Describe the Java syntax for exception handling
  • Write code to catch and handle exceptions
  • Generate code to handle user-input errors

10.2.1: About Exceptions

  • A common way to develop a program is to first make the code work assuming that nothing unusual happens
  • After the usual case works, then you start to consider the exceptional cases like:
    • Users enter letters when you want numbers
    • A file your program needs was moved or deleted
  • Java helps you to write your code in just this way
    1. You first write your code as if nothing unusual will happen
    2. When the usual case works correctly, you add code to handle exceptional cases
  • The mechanism to handle the unusual cases is known as exception handling
  • Exception handling is an important part of developing "solid" or "robust" programs
  • A solid or robust program means that you can run the program day after day
  • If crazy or unusual things happen, the program copes or at least recognizes that something is wrong

Terminology

  • Exception: an error condition that changes the normal flow of a program
  • Throw an exception: either the Java runtime or your code signals that something unusual happened
  • Catch an exception: take appropriate action to deal with an exception
  • Exception handler: the code that processes an exception

10.2.2: Exception Example

  • Many exceptions can occur because of user input errors
  • As an example, let us look at how you might handle user input errors

The Usual Case

  • Following is a simple program showing the usual case

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.*;

public class ReceiptCalculator {
    public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);
        double cost = 0, tax = 0;

        System.out.print("Enter net cost: ");
        cost = input.nextDouble();
        System.out.print("Enter tax: ");
        tax = input.nextDouble();
        double total = cost + tax;
        System.out.println("Total: " + total);

        System.out.println("Thanks for using us!");
    }
}

  • The program works for the usual case but can fail on invalid data
  • What happens if the user enters letters instead of numbers?
  • What if the user enters Ctrl-C
Enter net cost: $100
Exception in thread "main" java.util.InputMismatchException
        at java.util.Scanner.throwFor(Scanner.java:819)
        at java.util.Scanner.next(Scanner.java:1431)
        at java.util.Scanner.nextDouble(Scanner.java:2335)
        at ReceiptCalculator.main(ReceiptCalculator.java:9)
  • The program prints the message shown above and then ends
  • This is not desirable behavior, so we need to catch and handle the exception
  • In Java, you catch and handle exceptions with a try-catch block

10.2.3: Using try-catch

  • To catch and handle exceptions you use both try and catch statements
  • The code that can cause an exception goes inside a try block
  • Code to handle the exception goes inside a catch block
  • Syntax:
  • try {
      // One or more statements that can throw an exception
    } catch(Exception e) {
      // Exception handling code
      // Can have many catch blocks
    }
    

For Example

  • Here is an example with try and catch blocks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.*;

public class ReceiptCalculator2 {
    public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);
        double cost = 0, tax = 0;

        try {
            System.out.print("Enter net cost: ");
            cost = input.nextDouble();
            System.out.print("Enter tax: ");
            tax = input.nextDouble();
            double total = cost + tax;
            System.out.println("Total: " + total);
        } catch(InputMismatchException e) {
            System.out.println(
                "Error -- enter digits only!");
        } catch(NoSuchElementException e) {
            System.out.println("\nGoodbye!");
            System.exit(0);
        }
        System.out.println("Thanks for using us!");
    }
}

  • The program works the same way in the normal case
  • When the uses enters bad data, our program can do something about it now
  • Enter net cost: $100
    Error -- enter digits only!
    Thanks for using us!
    
  • Exiting when there is a user input error is usually not the best thing to do
  • Ideally, we want our program to:
    1. Describe the problem to the user
    2. Let the user correct the entry
  • However, our program does not allow the user to correct the problem yet
  • To allow the user to correct the problem, we must first understand an exception's flow of control

10.2.4: Exception Flow of Control

  • When an exception occurs while a method is executing:
    1. Method stops processing at the point of failure
    2. The code creates an object with the error information
    3. JVM tries to locate the exception handling code
    4. If the exception-handling code is found, the catch block gets the exception object
    5. If code cannot be found, the general exception handler is used
  • General exception handler displays an error messages on the console like the following and then ends the program
Exception in thread "main" java.util.InputMismatchException
        at java.util.Scanner.throwFor(Scanner.java:819)
        at java.util.Scanner.next(Scanner.java:1431)
        at java.util.Scanner.nextDouble(Scanner.java:2335)
        at ReceiptCalculator.main(ReceiptCalculator.java:9)
  • Let us trace through the flow for our example code
  1. The user enters bad data and the main() method stops processing
  2. First number: one
  3. The scanner object code creates an exception object of type InputMismatchException
  4. the JVM passes the exception object to the catch statement
  5. catch(InputMismatchException e)
  6. The exception handling code executes
  7. The program continues with the code after the catch block
  • Note that the program does not execute the second input statement
  • As soon as the error occurs, the program jumps to the exception handler
  • Program execution continues after the exception handler code

10.2.5: Trying Again

  • To allow the user to try again when there is an error, we need to code a loop
  • One way is to use a looping statement like the following

Example of Verification Using a Loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.util.*;

public class ReceiptCalculator3 {
    public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);
        double cost = 0, tax = 0;
        boolean valid = false;

        while (!valid) {
            try {
                System.out.print("Enter net cost: ");
                cost = input.nextDouble();
                System.out.print("Enter tax: ");
                tax = input.nextDouble();
                double total = cost + tax;
                System.out.println("Total: " + total);
                valid = true;
            } catch(InputMismatchException e) {
                System.out.println(
                    "Error -- enter digits only!");
                input.nextLine(); // clear the '\n'
            } catch(NoSuchElementException e) {
                System.out.println("\nGoodbye!");
                System.exit(0);
            }
        }
        System.out.println("Thanks for using us!");
    }
}

  • Running the program we see:
  • Enter net cost: 100
    Enter tax: $6
    Error -- enter digits only!
    Enter net cost: 100
    Enter tax: 6
    Total: 106.0
    Thanks for using us!
    
  • The program now allows the user to correct their errors and continue
  • However, the code requires the user to reenter all the numbers
  • A better solution is to reenter only the number in error
  • To do this we need to loop on each statement that could cause an exception
  • This leads to duplicate code
  • To eliminate the duplicate code, we use a method to handle the entire data input process

10.2.6: Verifying in Methods

  • Using a method we can group our input and verification code and reduce duplication
  • Running the program we see:
  • Enter net cost: ten
    Error -- enter digits only!
    Enter net cost: 10
    Enter tax: $1.23
    Error -- enter digits only!
    Enter tax: 1.23
    Total: 11.23
    Thanks for using us!
    
  • Users can correct individual errors without having to redo all their entries
  • Also note how much simpler the code in main() appears

Example of Verification Using a Method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.*;

public class ReceiptCalculator4 {
    public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);
        double cost = 0, tax = 0;

        cost = readDouble(input, "Enter net cost: ");
        tax = readDouble(input, "Enter tax: ");
        double total = cost + tax;
        System.out.println("Total: " + total);

        System.out.println("Thanks for using us!");
    }

    /**
     * Read a double from the console.
     *
     * @param input Scanner object to read from.
     * @param prompt User prompt to show before input
     * @return A double entered by the user.
     */
    public static double readDouble(Scanner input,
            String prompt) {
        double number = 0;
        try {
            System.out.print(prompt);
            number = input.nextDouble();
        } catch(InputMismatchException e) {
            System.out.println(
                "Error -- enter digits only!");
            input.nextLine(); // clear the '\n'
            return readDouble(input, prompt);
        } catch(NoSuchElementException e) {
            System.out.println("\nGoodbye!");
            System.exit(0);
        }
        return number;
    }
}

  • Note that there is still a loop in the readDouble() method -- can you see it?
  • Programmers commonly develop a library of static input methods like these

10.2.6: Summary

  • A common way to develop a program is to first make the code work assuming that nothing unusual happens
  • After the usual case works, then you consider the exceptional cases
  • Java provides exception handling to handle these exceptional cases
  • Many exceptions can occur because of user input errors
  • To catch and handle exceptions you use both try and catch statements
  • try {
      // One or more statements that can throw an exception
    } catch(Exception e) {
      // Exception handling code
      // Can have many catch blocks
    }
    
  • To allow users to correct their errors, you need to add a looping mechanism around the input statement
  • boolean valid = false;
    while (!valid) {
        try {
            System.out.print("Enter net cost: ");
            cost = input.nextDouble();
            // May have more statements
        } catch(InputMismatchException e) {
            System.out.println(
                "Error -- enter digits only!");
            input.nextLine(); // clear the '\n'
        } // may need more catch statements
    }
    
  • Since input is a frequent occurrence, it is common to write user input methods
  • One example is readDouble():
  • public static double readDouble(Scanner input,
            String prompt) {
        double number = 0;
        try {
            System.out.print(prompt);
            number = input.nextDouble();
        } catch(InputMismatchException e) {
            System.out.println(
                "Error -- enter digits only!");
            input.nextLine(); // clear the '\n'
            return readDouble(input, prompt);
        } catch(NoSuchElementException e) {
            System.out.println("\nGoodbye!");
            System.exit(0);
        }
        return number;
    }
    
  • You can simplify the code for looping on error by using recursion
  • return readDouble(input, prompt);

Exercise 10.2

Take one minute to prepare answers to the following questions:

  1. What two statements are required to catch and handle exceptions?
  2. What are the advantages and disadvantages of writing a method for user input?

10.3: Customizing Exceptions

Objectives

At the end of the lesson the student will be able to:

  • Throw an exception
  • Explain the difference between checked and unchecked exceptions
  • Use predefined Exception classes
  • Write a custom class that defines a new exception

10.3.1: Using the throw Statement

  • You may be wondering how the code in Scanner and other classes generates an exception
  • The answer is the Java throw statement
  • Syntax:
  • throw ThrowableObject
  • The Exception class is a subclass of Throwable, so we can throw an Exception object
  • For example:
  • throw new Exception("Exception message");
  • Typically, you decide to throw an exception after checking for an error condition
  • if (cost < 0) {
        throw new Exception(
            "Cost cannot be less than 0");
    }
    
  • To demonstrate, let us throw an exception in an example program

Example Program Using throw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.util.*;

public class ReceiptCalc {
    public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);
        double cost = 0, tax = 0;
        boolean valid = false;

        while (!valid) {
            try {
                System.out.print("Enter net cost: ");
                cost = input.nextDouble();
                if (cost < 0) {
                    throw new Exception(
                        "Cost cannot be less than 0");
                }
                System.out.print("Enter tax: ");
                tax = input.nextDouble();
                if (tax < 0) {
                    throw new Exception(
                        "Tax cannot be less than 0");
                }
                double total = cost + tax;
                System.out.println("Total: " + total);
                valid = true;
            } catch(Exception e) {
                String message = e.getMessage();
                System.out.println(message);
                input.nextLine(); // clear the '\n'
            }
        }
        System.out.println("Thanks for using us!");
    }
}

  • Note the use the getMessage() method to explain the error
  • There are a few other commonly used exception methods shown in the table below

When to Throw an Exception

  • To report an error before handling the condition
    • For example: report an error to the user then ask to reenter data
  • When a method encounters a situation where it cannot complete its task
    • For example: cannot write to an already-opened file

Commonly Used Methods of the Throwable Class

Method Description
getMessage() Returns the message associated with the exception, if available.
printStackTrace() Prints the stack trace to the standard error stream.
toString() Returns a string with the name of the exception class along with the message associated with the exception, if available.

10.3.2: Predefined Exception Classes

  • There are more exception classes than the single class Exception
  • Many Java library classes throw exceptions
  • API documentation or class interface will tell you
  • Some of them are shown in the following tree
  • You can also write your own exceptions, which we will cover in the following sections
java.lang.Throwable
  |
  +--java.lang.Error (Unchecked)
  |
  +--java.lang.Exception (Checked)
       |
       +--java.lang.InterruptedException
       |
       +--java.io.IOException
       |
       +--java.lang.RuntimeException (Unchecked)
            |
            +--java.lang.ArithmeticException
            |
            +--java.util.InputMismatchException
            |
            +--java.lang.IndexOutOfBoundsException
            |
            +--java.lang.NullPointerException
            |
            +--java.util.NoSuchElementException
  • Throwable is the root class of all exceptions
    • Has the commonly used methods for all errors and exceptions
  • Error means that a serious problem has occurred
    • Applications should not try to catch these types of problems
  • Exception is the root class of exceptions that a reasonable program might catch
  • RuntimeException are errors caught by the JVM rather than the compiler
    • Usually due to program bugs
  • All exceptions other than Error and RuntimeException (and subclasses) are checked exceptions
    • Compiler forces you to deal with the exception
  • Predefined exceptions usually include a meaningful message that is retrieved with method getMessage
  • System.out.println(e.getMessage());

10.3.3: Types of Exceptions

  • Before we write out own exceptions, we need to know which type to write
  • Two fundamental types of errors that cause exceptions

Checked Exceptions

  • First type happens because the program cannot get a resource
    • Problem is caused by the external resource
    • Programmer has no control over the resource
  • Java forces these types of problems to be provided for if they occur
  • Compiler checks that some mechanism is in place for receiving and processing the exception object
  • Since it is checked by the compiler, known as a checked exception
  • An example of this type of exception is the IOException
  • Programmer cannot prevent an I/O device failure (e.g. disk drive failure)
  • Thus, need to check if the condition has occurred

Unchecked Exception

  • Second type happens as a result of a programming error
  • We saw exceptions of this type in our example program
  • User can enter a string that cannot be converted to a number
  • Another example is when the user presses Ctrl-C buttons
  • Both of these errors can always be prevented by programming
    • If they occur in your homework programs, it will affect your score

10.3.4: Writing Custom Exception Classes

  • You can define your own exception class
  • There are two main reasons to write your won exception class:
    • To carry the precise information you want thrown to the catch block
    • To have a different type for every kind of exceptional case
  • You must derived your exception from some already defined exception class
  • Often all you need to code is the constructors
  • You should always define two constructors for an exception class:
    • A constructor taking no arguments that defines a default message string and calls the superclass constructor
    • A constructor that takes a String message argument and calls the superclass constructor
  • Following is an example of a custom exception class

Custom Exception Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class DivisionByZeroException extends Exception {
    /**
     * Default constructor with a default error message.
     */
    public DivisionByZeroException() {
        super("Division by zero!");
    }

    /**
     * Overloaded constructor for custom error message.
     *
     * @param message The custom error message.
     */
    public DivisionByZeroException(String message) {
        super(message);
    }
}

Program Using the Custom Exception

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.util.*;

public class Divide2Nums {
    public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);
        double numerator = 0, denominator = 0;
        double quotient = 0;
        boolean valid = false;

        numerator = readDouble(input,
            "Enter numerator: ");
        while (!valid) {
            try {
                denominator = readDouble(input,
                    "Enter denominator: ");
                if (denominator == 0) {
                    throw new DivisionByZeroException();
                }
                quotient = numerator / denominator;
                valid = true;
            } catch (DivisionByZeroException e) {
                System.out.println(e.getMessage());
            }
        }
        System.out.println(numerator + " / "
            + denominator + " = " + quotient);
    }

    /**
     * Read a double from the console.
     *
     * @param input Scanner object to read from.
     * @param prompt User prompt to show before input
     * @return A double entered by the user.
     */
    public static double readDouble(Scanner input,
            String prompt) {
        double number = 0;
        try {
            System.out.print(prompt);
            number = input.nextDouble();
        } catch(InputMismatchException e) {
            System.out.println(
                "Error -- enter digits only!");
            input.nextLine(); // clear the '\n'
            return readDouble(input, prompt);
        } catch(NoSuchElementException e) {
            System.out.println("\nGoodbye!");
            System.exit(0);
        }
        return number;
    }
}

10.3.5: Multiple catch Blocks

  • A try block can throw any number of exceptions of differing types
  • In any one execution of the try block, only one of the possible exception can be thrown
  • However, different types of exceptions can be thrown on different executions of the try block
  • Each catch block can only catch one type of exception
  • Syntax:
  • try {
      // One or more statements that can
      // throw an exception
    } catch(MostSpecificException e) {
      // Exception handling code
    } catch(LeastSpecificException e) {
      // Exception handling code
    }
    
  • When catching multiple exceptions, the order of the catch blocks is important
  • When an exception is thrown, the catch blocks are examined in order
  • The first catch block that matches the type of the exception is executed
  • Thus you generally want to place the most specific exceptions first

Example with Multiple catch Blocks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.util.*;

public class Divide2Nums2 {
    public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);
        double numerator = 0, denominator = 0;
        double quotient = 0;
        boolean valid = false;

        numerator = readDouble(input,
            "Enter numerator: ");
        while (!valid) {
            try {
                denominator = readDouble(input,
                    "Enter denominator: ");
                if (denominator == 0) {
                    throw new DivisionByZeroException();
                }
                quotient = numerator / denominator;
                valid = true;
            } catch (DivisionByZeroException e) {
                System.out.println(e.getMessage());
            } catch (Exception e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
                System.exit(1);
            }
        }
        System.out.println(numerator + " / "
            + denominator + " = " + quotient);
    }

    /**
     * Read a double from the console.
     *
     * @param input Scanner object to read from.
     * @param prompt User prompt to show before input
     * @return A double entered by the user.
     */
    public static double readDouble(Scanner input,
            String prompt) {
        double number = 0;
        try {
            System.out.print(prompt);
            number = input.nextDouble();
        } catch(InputMismatchException e) {
            System.out.println(
                "Error -- enter digits only!");
            input.nextLine(); // clear the '\n'
            return readDouble(input, prompt);
        } catch(NoSuchElementException e) {
            System.out.println("\nGoodbye!");
            System.exit(0);
        }
        return number;
    }
}
  • What would happen if the order of the exceptions was reversed?
  • For checked exceptions, the compiler will report these problems
Divide2Nums2.java:23:
   exception DivisionByZeroException has already been caught
        } catch (DivisionByZeroException e) {

10.3.6: When to Define Your Own Exceptions

  • When you use a throw-statement in your code you usually define your own exception class
  • Using a predefined, more general exception class means your catch-block will have to be general
  • More general catch-blocks can also catch exceptions that should be handled somewhere else
  • Coding a specific catch-block for your own exception class will catch the exceptions it should and pass others on

10.3.7: Summary

  • To throw an exception, you code a throw statement:
  • throw new Exception("Exception message");
  • Typically, you decide to throw an exception after checking for an error condition
  • if (cost < 0) {
        throw new Exception(
            "Cost cannot be less than 0");
    }
    
  • When you catch an exception, you can use getMessage() to display the error message associated with the exception
  • System.out.println(e.getMessage());
  • When throwing an exception, you can use a predefine exception class or write a custom exception class
  • You must derived your exception from some already defined exception class
  • There are two classifications of exceptions:
  • Checked exception: the compiler forces you to code an exception handler
  • Unchecked exception: the compiler does NOT force you to code an exception handler
  • You should always define two constructors for a custom exception class:
    • A constructor taking no arguments that defines a default message string and calls the superclass constructor
    • A constructor that takes a String message argument and calls the superclass constructor
  • For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class DivisionByZeroException extends Exception {
    /**
     * Default constructor with a default error message.
     */
    public DivisionByZeroException() {
        super("Division by zero!");
    }

    /**
     * Overloaded constructor for custom error message.
     *
     * @param message The custom error message.
     */
    public DivisionByZeroException(String message) {
        super(message);
    }
}
  • A try block can throw any number of exceptions of differing types
  • Each catch block can only catch one type of exception
  • When an exception is thrown, the catch blocks are examined in order
  • The first catch block that matches the type of the exception is executed
  • Thus you need to code catch blocks with the most specific exception first

Exercise 10.3

Take one minute to prepare answers to the following questions:

  1. What output is produced by the following code?
  2. class WaitTimeException extends Exception {
        public WaitTimeException() {
            super("Time expired");
        }
    
        public WaitTimeException(String message) {
            super(message);
        }
    }
    
    public class WaitTime {
        public static void main(String[] args) {
            int waitTime = 50;
            System.out.println("Before try-block");
            try {
                System.out.println("Entering try-block");
                if (waitTime > 30)
                    throw new WaitTimeException();
                System.out.println("Exiting try-block");
            } catch(WaitTimeException e) {
                System.err.println("WTE: "
                    + e.getMessage());
            } catch(Exception e) {
                System.err.println("Exception: "
                    + e.getMessage());
            }
            System.out.println("After catch-block");
        }
    }
    

10.4: More Exception Topics

Objectives

At the end of the lesson the student will be able to:

  • Use the throws clause
  • Use the finally block

10.4.1: Using the throws Clause

  • Any method that can cause an exception must deal with it
  • If you decide the method cannot handle the exception, use the throws clause to send the exception to the caller
  • General syntax for throwing an exception:
  • returnType functionName(paramterList)
        throws ExceptionType1, ExceptionType2,... {
        // method body
    }
    
  • Throwing an exception is like passing the buck
    • Requires the calling method to deal with the exception
  • The calling method can also throw the exception
  • You can even throw an exception from the main() method
  • public static void main(String[] args)
        throws java.io.IOException {
    
  • Eventually some method should catch it
    • Otherwise the general exception handler is used

How Exceptions are Propagated

  • When methods cannot handle an exception, that method should throw the exception
  • The user of the method can then decide how to handle the exception
    • Note that the Java API has many methods that throw exceptions
  • Methods can call other methods that can throw an exception
  • This chain continues usually until one method catches the exception

For Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import java.util.*;

public class Divide2Nums3 {
    public static void main(String[] args) {
        Scanner input  = new Scanner(System.in);
        double numerator = 0, denominator = 0;
        double quotient = 0;
        boolean valid = false;

        numerator = readDouble(input,
            "Enter numerator: ");
        while (!valid) {
            try {
                denominator = readDouble(input,
                    "Enter denominator: ");
                quotient =
                    divide(numerator, denominator);
                valid = true;
            } catch (DivisionByZeroException e) {
                System.out.println(e.getMessage());
            } catch (Exception e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
                System.exit(1);
            }
        }
        System.out.println(numerator + " / "
            + denominator + " = " + quotient);
    }

    static double divide(double numer, double denom)
            throws DivisionByZeroException {
        if (denom == 0) {
            throw new DivisionByZeroException();
        }
        return numer / denom;
    }

    /**
     * Read a double from the console.
     *
     * @param input Scanner object to read from.
     * @param prompt User prompt to show before input
     * @return A double entered by the user.
     */
    public static double readDouble(Scanner input,
            String prompt) {
        double number = 0;
        try {
            System.out.print(prompt);
            number = input.nextDouble();
        } catch(InputMismatchException e) {
            System.out.println(
                "Error -- enter digits only!");
            input.nextLine(); // clear the '\n'
            return readDouble(input, prompt);
        } catch(NoSuchElementException e) {
            System.out.println("\nGoodbye!");
            System.exit(0);
        }
        return number;
    }
}

10.4.2: Using the finally Block

  • The finally block is an optional section that follows the catch blocks
  • The finally block always executes whether or not an exception is thrown
  • Syntax:
  • try {
      // One or more statements that can
      // throw an exception
    } catch(MostSpecificException e) {
      // Exception handling code
    } catch(LeastSpecificException e) {
      // Exception handling code
    } finally {
      // Optional section that always executes
    }
    //Executes unless an uncaught exception is thrown
    
  • The finally block is often used to dispose of external resources such as:
    • Database connections
    • File descriptors
    • Graphics contexts
    • Sockets
  • External resources depend on code outside of Java
  • If these resources are scarce then you want to free them as soon as possible
  • Most of these types of resources have a close() or a dispose() method
  • g.dispose();
  • Note that the finally block is needed because the code following the catch blocks does not execute if an uncaught exception is thrown

10.4.3: Rethrowing an Exception

  • A catch block can have code that throws an exception
  • Sometimes you want to catch an exception, examine and then rethrow it
  • For example:
  • catch (IOException e) {
      System.err.println("IOException thrown in method foo");
      throw e;
    }
    

10.4.4: Summary

  • If a method cannot handle the exception, it should throw the exception to the calling method
  • To throw an exception you add a throws clause in the method header
  • static double divide(double numer, double denom)
            throws DivisionByZeroException {
    
  • The finally block is an optional section that follows the catch blocks
  • The finally block always executes whether or not an exception is thrown
  • A catch block can have code that throws an exception
  • Sometimes you want to catch an exception, examine and then rethrow it

Exercise 10.4

Take one minute to prepare answers to the following questions:

  1. What output is produced by the following code?
  2. What would happen if the code throw e; were uncommented
  3. class WaitTimeException extends Exception {
        public WaitTimeException() {
            super("Time expired");
        }
    
        public WaitTimeException(String message) {
            super(message);
        }
    }
    
    public class WaitTime2 {
        public static void main(String[] args) {
            int waitTime = 50;
            System.out.println("Before try-block");
            try {
                System.out.println("Entering try-block");
                if (waitTime > 30)
                    throw new WaitTimeException();
                System.out.println("Exiting try-block");
            } catch(WaitTimeException e) {
                System.err.println("WTE: "
                    + e.getMessage());
                // throw e
            } catch(Exception e) {
                System.err.println("Exception: "
                    + e.getMessage());
            } finally {
                System.out.println("Finally done");
            }
            System.out.println("After catch-block");
        }
    }
    

Wrap Up

Home | WebCT | Announcements | Schedule | Room Policies | Course Info
Help | FAQ's | HowTo's | Links

Last Updated: April 16 2005 @16:42:38