Concepts / Exception Handling with try-catch

Exception Handling with try-catch

The actionPerformed method is the entry point for handling a button press, and it receives an ActionEvent describing that press.

  • Programming

Testing a Common Belief About Handlers

A button handler in a graphical program is easy to picture as a list of steps that always runs from top to bottom. Many beginners assume that if the user types a bad value into one text box, the handler shows an error message and then carries on to compute something anyway. A second version of the same belief says that every kind of mistake inside the handler is caught by the same kind of try-catch block. This article tests both beliefs against a real event handler written for a Swing calculator, which runs when the user presses one of the operator buttons.

What do you think happens?

The user types 8 into the x box, types 0 into the y box, and presses the divide button. Does the handler perform the division?

  • Yes, and then it shows an error

  • No, the division is skipped and an error message is shown

Reveal answer
Answer:

No, the division is skipped and an error message is shown

The handler tests the value of y with an if statement before it divides. If y equals 0, it sets the answer label to 'Can't divide by zero!' and the division itself is not performed. Division by zero is therefore not handled with a try-catch block in this design.

How a Button Press Reaches the Handler

The actionPerformed method is the entry point for every button press in this design. The application does not call it directly. Swing calls actionPerformed with an ActionEvent object that describes the interaction, and the method is the place where the application decides what that interaction means. The order of events runs from the user's click, to the event system, to the handler's code, as the diagram below shows.

Userpresses operator buttonSwing event systemdelivers the pressactionPerformedreceives ActionEventx and y text boxesread as textAnswer labelshows result or error1. clicks button2. calls with ActionEvent3. reads both boxes4. writes result or message
What is the order of events from the user clicking the button, to the event system calling actionPerformed with an ActionEvent, to the handler's code running?

The handler's code runs only after the event system has delivered the press. Everything the handler does for that press happens inside that one call. When the method returns, that button press is finished, and the next press starts a new call.

Tracing the Handler's Decisions

The handler has two jobs that happen in sequence. The first job turns the two text boxes into numbers. The second job picks one arithmetic operation based on the button that was pressed and writes its result. Keeping these jobs separate makes it easier to see where a failure can occur and what the user should see afterward.

Button pressedactionPerformed calledParse xlegal number?Error for xlabel set, returnError for ylabel set, returnCompute resultadd, subtract, multiplyCan't divide by zero!division not performedComputed resultresult shownParse ylegal number?Which operator?button pressedy equals 0?divide onlyCompute x / ydivision performednoyesnoyesadd, subtract, multiplydivideyesno
When an error occurs inside actionPerformed, which statements run, which are skipped, and at what point does control jump to the catch block?

Read the diagram as a set of exits. The x test and the y test lead to error terminals that stop the handler before any arithmetic happens. The operator test has one branch that is not a simple match: divide passes through an extra check on y before any division is performed. Only the paths that reach the computed result terminal are successful button presses. Follow the no arrows from the two parsing tests first, because those are the paths where the method ends early.

The first belief from the introduction is therefore false for this handler. The source's design does not continue after reporting a bad input, because the return ends the method first.

A try Block for Bad Input

The following sketch illustrates the input-reading pattern described in the source. The field names xField, yField, and answerLabel are placeholders chosen for this example, not names taken from the source, and the rest of the class is omitted.

Code walkthrough
public void actionPerformed(ActionEvent e) {
    double x;
    try {
        x = Double.parseDouble(xField.getText());
    } catch (NumberFormatException ex) {
        answerLabel.setText('Please enter a number for x');
        xField.requestFocusInWindow();
        return;
    }
    // ... y is read the same way, then the operator is chosen
}
  1. 1
    The method signature is the entry point Swing calls for a button press.
  2. 2
    The try block contains the one statement that may fail on bad input.
  3. 3
    If parsing fails, the catch clause sets the label, moves focus to the x box, and returns.
  4. 4
    If parsing succeeds, control skips the catch clause and continues with the rest of the method.
  • The method receives an ActionEvent from Swing for each button press
  • Double.parseDouble is the statement that can fail on illegal text
  • The catch clause runs only for NumberFormatException
  • return ends the method, so the code after the catch never runs for this press

Division by Zero Uses an if Test

The second belief from the introduction says that division by zero is handled like bad input, with a try-catch block around the division. The source does not do this. The comment in the handler says that division by zero produces an error message, and the division branch tests the value of y with an if statement before it divides. The check happens in advance, so the division is never attempted when y is 0.

Double.parseDoublemay throw on bad texty == 0 testchecked before dividingNumberFormatExceptioncaught by catch clauseError messageCan't divide by zero!returnmethod ends for this pressDivision skippedx / y never computedthrowscatch runsyesthen
How does the program's control flow differ when an error is handled by try-catch versus when it is checked in advance with an if statement?

The two mechanisms look similar from the user's side, since both show a message in the answer label. Inside the handler they differ. A try-catch block reacts after an operation has failed, by jumping to the catch clause. An explicit if test is checked before the risky operation runs, so the operation is simply not attempted. Both can be used to keep a bad computation from running, but only the if test prevents the division from being performed at all.

Before
result = x / y;

Division runs even when y is 0

After
if (y == 0) {
    answerLabel.setText('Can't divide by zero!');
} else {
    answerLabel.setText(String.valueOf(x / y));
}

The y == 0 test runs first, and the division is skipped when it is true

Mistakes Beginners Make

  • Common mistake

    Assuming the handler keeps running after a bad input is reported

    What it looks like

    The user types abc into the x box, and the programmer expects the handler to show a message and then still compute the answer.

    Why it fails

    Each catch clause ends with return, so the method ends for that button press before any arithmetic happens.

    Do this instead

    Trace each return statement in order and note that it ends the method for that press.

  • Common mistake

    Wrapping every risky operation in try-catch, including division by zero

    What it looks like

    A try block is placed around x / y so that a zero y is caught as an error.

    Why it fails

    The source handles division by zero with an explicit y == 0 test before the division, not with a try-catch block.

    Do this instead

    Use an if test to check the value of y before dividing, and keep try-catch for the input parsing.

  • Common mistake

    Forgetting which path reaches the result

    What it looks like

    A learner sees the answer label updated after a bad input and concludes the error path did not stop the handler.

    Why it fails

    The label may have been set by an earlier error message, and the successful result is only written on the computed result path.

    Do this instead

    Find the terminal where the result is written and check which decisions must be true to reach it.

  • Common mistake

    Believing that a single try block around the whole handler is required for correct behavior

Practice Tracing a Press

EASY

Using the flowchart from this article, trace a press of the divide button in which the user types 12 into the x box and 4 into the y box. List, in order, each decision the handler makes and state which statement writes the final answer.

Hints
  • Start at the Button pressed terminal and follow the yes arrow from each parsing test, since both values are legal numbers.
  • At the operator test, follow the divide branch, then check whether y equals 0.
  • The result is written on the computed result path after the division is performed.
MEDIUM

Trace the same handler for a press of the divide button in which the user types abc into the x box and 0 into the y box. Name the one statement that ends the method, and state whether the y == 0 test is ever reached.

Hints
  • The x parsing test fails first, which determines where the handler stops.
  • Look at which catch clause runs and what it does last.

Key Takeaways

  • The actionPerformed method is the entry point for a button press, and Swing calls it with an ActionEvent describing that press.
  • Input errors from Double.parseDouble are handled with try-catch, and each catch clause ends with return, so the handler stops early for that press.
  • Division by zero is checked with an explicit y == 0 test before the division, not with a try-catch block.
  • To find where a handler diverged from what you expected, trace each decision and return statement in order and note which branch ran.