Concepts / Exceptions and try..catch in Java

Exceptions and try..catch in Java

A try..catch block lets a program continue after a runtime error. When an exception occurs, the rest of the try block is skipped and the catch clause runs.

  • Programming

A Program That Must Survive a Bad File

Imagine a small program that reads numbers from a file whose name the user types in. It then reports how many numbers it read, their sum, and their average. This is the program used in this exercise, named AverageNumbersFromFile. It sounds simple, but the file can be bad in two different ways. The file name may not point to a readable file, and the file may contain something other than numbers of type double. A program that does not plan for either situation would stop at the first problem. The program is designed to survive both, and the tool that makes this possible is the try..catch block.

What do you think happens?

If the file holds the values 3.5, 4.0, a token that is not a number, and then 10.0, how many numbers does the program report as read?

  • Four, because all four tokens appear in the file

  • Two, because the loop stops at the first value that cannot be read as a double

  • Three, because the bad token is counted but skipped

Reveal answer
Answer:

Two, because the loop stops at the first value that cannot be read as a double

The source states that the output is the sum and average of the values read successfully before the first problem. The 10.0 after the bad token is never reached, so it is not included.

What a Runtime Error Is

Definition

A runtime error is a problem that appears while the program is running, not a mistake that prevents the program from compiling. Reading a file is a common source of runtime errors. The file may not exist, may not be readable, or may contain data in an unexpected form.

Without any handling, one of these problems would stop the program. Exception handling gives the program a way to respond to such a problem and then keep going. The phrase exception handling describes the whole approach, and try..catch is the Java syntax that carries it out.

Definition

A try..catch block lets a program continue after a runtime error. When an exception occurs, the rest of the try block is skipped and the catch clause runs.

The Shape of a try..catch Handler

A try..catch handler has two parts. The try part holds the statements that might fail. The catch part names the kind of exception it handles and holds the code that runs when that exception occurs. The schematic below uses the general form only. The exercise's own calls are described in the sections that follow.

java
Notes on the code
  • The try part is the code the program attempts.
  • The catch part names the exception type it handles.
  • The catch body runs only when that exception is thrown.

The exercise uses this same pattern twice. The call to TextIO.readFile is in the try part of the first handler, and IllegalArgumentException is caught in its catch part. The second handler wraps the loop that calls TextIO.getDouble() repeatedly. Both handlers catch IllegalArgumentException, but the code in each catch clause is different because the two blocks serve different purposes.

Tracing the Reading Loop

The second try..catch wraps the reading loop. On each pass, the loop calls TextIO.getDouble(). Each successful call is followed by a count increment and an addition to the sum. The clearest way to understand the loop is to watch count and sum change from pass to pass. The example below uses a generated file that holds 3.5, 4.0, a token that cannot be read as a double, and then 10.0.

Pass 1read 3.5, count 1, sum 3.5Pass 2read 4.0, count 2, sum 7.5Pass 3exception, count 2, sum 7.5Loop ends10.0 never readnext passnext passcatch runs
On each pass, what are the values of count and sum, and how does the exception on the third pass change the values for the passes that follow?
Worked example

Reading 3.5, 4.0, a bad token, then 10.0

Starting with count 0 and sum 0.0, trace how the loop updates count and sum, and state the final output.

  1. 1
    Pass 1

    The value 3.5 is read successfully. The value is stored, count becomes 1, and sum becomes 3.5.

  2. 2
    Pass 2

    The value 4.0 is read successfully. Count becomes 2, and sum becomes 7.5.

  3. 3
    Pass 3

    The token cannot be read as a double, so an exception is thrown. The rest of the try block is skipped, so count and sum keep the values 2 and 7.5. Control moves to the catch clause.

  4. 4
    After the catch

    The loop does not run again. The program moves on to the results, which use count 2 and sum 7.5.

Result

The program reports 2 numbers read, a sum of 7.5, and an average of 3.75. The 10.0 at the end of the file is not included, because the first exception ended the loop.

Where Execution Goes After an Exception

The flowchart below shows the path that execution takes on each pass through the try block. At the decision point, the program asks whether the value was read successfully. If the answer is no, the value is stored, the count goes up, and the value is added to the sum, and then the loop repeats. If the answer is yes, the rest of the try block is skipped. The count and sum keep the values they had at that moment, and control moves directly to the catch clause.

Enter try blockRead next valuecall getDoubleRead succeeded?Update count and sumcount goes up, sum growsSkip rest of tryblockcount and sum unchangedCatch clause runsPrint resultsafter try..catchno exceptionrepeat loopexceptionjump to catchcontinue
After an exception is thrown partway through the try block, which path does execution take: back to the failing statement, out of the try block into the catch clause, and then onward to the code after the try..catch?

Why the End of File Is Not an Error

The loop reads until the data runs out, and running out of data causes an exception too. The source explains that this end-of-file IllegalArgumentException is expected and is not treated as an error, so its catch clause is intentionally empty. The loop stops, and the program reports its results normally. A genuine runtime error, such as an unreadable file name, is handled differently because the catch clause has real work to do.

SituationWhat the program expectsWhat the catch clause doesWhat the user sees
End of file reached in the reading loopThe data simply runs outNothing; the catch body is intentionally emptyThe results for the numbers read so far
File name does not point to a readable fileA real problem that must be addressedResponds to the problem and lets the program continueA handled response, not a crash
Value in the file is not a doubleThe data is not in the expected formEnds the reading loop; the output covers values read before the problemSum and average of the values read successfully

Expected events and genuine errors handled by try..catch in this exercise

Best practice

When you write your own handler, decide whether the exception represents a real error or an expected event. If the situation is an error, the catch clause should report it or recover from it. If the situation is an expected event, the catch clause may be short. This program uses both kinds of handling, which makes it a useful contrast.

Mistakes Readers Make With Handlers

  • Common mistake

    Assuming the failing statement is retried

    What it looks like

    A reader expects the bad token to be read again on the next pass.

    Why it fails

    When an exception occurs, the rest of the try block is skipped and the catch clause runs. Control does not return to the statement that failed.

    Do this instead

    Trace the program by following the flowchart: after the catch clause, execution moves on to the code after the try..catch.

  • Common mistake

    Expecting count and sum to include the value that caused the exception

    What it looks like

    A reader adds the bad value or the 10.0 after it to the total.

    Why it fails

    The count and sum keep the values they had at the moment the exception occurred. The values after the problem are never read.

    Do this instead

    Use the values from before the exception. In the generated example, the result is 2 values and a sum of 7.5.

  • Common mistake

    Treating every caught exception as a failure to report

    What it looks like

    A reader adds an error message to the end-of-file catch clause.

    Why it fails

    The source states that the end-of-file exception is expected and is not treated as an error, so its catch clause is intentionally empty.

    Do this instead

    Decide whether the exception is a real error or an expected event before writing the catch body.

  • Common mistake

    Forgetting that a runtime error is not a compile-time error

Trace a Different File

MEDIUM

A generated file contains the values 2.0, 6.0, 1.0, a token that is not a double, and then 8.0. Trace the reading loop. What count and sum does the program report, and which value is not included?

Hints
  • Track count and sum after each successful read, starting from zero.
  • The rest of the try block is skipped at the exception, so the values after the bad token are never read.
  • The 1.0 is read before the bad token, so it is included in the results.
EASY

Explain in one or two sentences why the end-of-file exception and the bad-token exception in the reading loop are handled differently, using the words expected and error.

Hints
  • Look at what the source says about the end-of-file catch clause.
  • Consider whether the bad token is a real problem in the data.

Key Takeaways

  • A try..catch block lets a program continue after a runtime error. When an exception occurs, the rest of the try block is skipped and the catch clause runs.
  • After the catch clause finishes, execution does not return to the failing statement. It moves on to the code after the try..catch.
  • In the reading loop, count and sum keep the values they had when the exception occurred, so the results cover only the values read successfully before the problem.
  • The end-of-file IllegalArgumentException is expected in this exercise, so its catch clause is intentionally empty, while a genuine error needs a catch clause that responds to it.