Skip to content
wannacode

Different errors and finally

Problem

The bill for zero people

The program splits the restaurant bill evenly. You already know about wrong input, and you catch it:

Main.java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
try {
int bill = Integer.parseInt(in.nextLine());
int people = Integer.parseInt(in.nextLine());
System.out.println("Per person: €" + bill / people);
} catch (NumberFormatException e) {
System.out.println("Enter whole numbers.");
}
}
}

The bill is €90, and someone enters 0 for the number of people. The program stops again:

Error
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:9)

catch is there, but it does not help. It catches only NumberFormatException, and this is a different kind of exception.

The idea

Several catch blocks

One try can be followed by several catch blocks, one for each kind of error:

Scanner in = new Scanner(System.in);
try {
int bill = Integer.parseInt(in.nextLine());
int people = Integer.parseInt(in.nextLine());
System.out.println("Per person: €" + bill / people);
} catch (NumberFormatException e) {
System.out.println("Enter whole numbers.");
} catch (ArithmeticException e) {
System.out.println("People cannot be 0.");
}
Input Output
90 and 3 Per person: €30
90 and 0 People cannot be 0.
90 and three Enter whole numbers.

The blocks are checked from top to bottom. The first one whose kind matches runs, and only that one. The rest are skipped.

Scanner in = new Scanner(System.in);
try {
int bill = Integer.parseInt(in.nextLine());
int people = Integer.parseInt(in.nextLine());
System.out.println("Per person: €" + bill / people);
} catch (NumberFormatException e) {
System.out.println("Enter whole numbers.");
} catch (ArithmeticException e) {
System.out.println("People cannot be 0.");
}
Step by step, in words
  1. First run: the bill is €90, and there are 0 people.
  2. 90 / 0 is division by zero: ArithmeticException is thrown.
  3. The first catch is for NumberFormatException. It does not match, so it is skipped.
  4. The second one matches. It runs, and only it.
  5. Second run: "three" is typed in instead of the number of people.
  6. parseInt cannot make a number: NumberFormatException is thrown.
  7. The very first catch matches. The second is never reached.
  8. The blocks are checked from top to bottom. The first one that matches runs.
More precisely, if you are curious
  • When two kinds are handled the same way, you can catch them in one block with |: catch (NumberFormatException | ArithmeticException e).

The idea

The family of exceptions

Exceptions are classes, related by inheritance. Here are the most common ones:

The hierarchy
Throwable
├── Error a serious JVM problem, not caught
│ ├── OutOfMemoryError
│ └── StackOverflowError
└── Exception
├── IOException files, network
├── InterruptedException
└── RuntimeException
├── ArithmeticException
├── IllegalArgumentException
│ └── NumberFormatException
├── IndexOutOfBoundsException
│ └── ArrayIndexOutOfBoundsException
└── NullPointerException

catch catches the kind you name and all of its subclasses. This is the polymorphism from the module on inheritance: a variable of a parent type can point to an object of a subclass. That is why catch (Exception e) catches everything:

static void split(String billText, String peopleText) {
try {
int bill = Integer.parseInt(billText);
int people = Integer.parseInt(peopleText);
System.out.println("Per person: €" + bill / people);
} catch (Exception e) {
System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage());
}
}
split("90", "3");
split("90", "0");
split("90", "three");
Output
Per person: €30
ArithmeticException: / by zero
NumberFormatException: For input string: "three"

e.getClass().getSimpleName() gives the name of the object's real class. The variable is of type Exception, but the object is of a subclass.

More precisely, if you are curious
  • Error and its subclasses are problems of the JVM itself, such as running out of memory or a stack overflow. The JVM itself throws them. The program usually cannot do anything sensible after them, so they are not caught.
  • catch (Throwable t) would catch them too. Do not do it.
  • Catch as specifically as you can. catch (Exception e) also hides errors you did not expect, such as a bug in your own code.

Try it

Which catch?

What will the program print?

int[] seats = { 4, 2, 6 };
try {
System.out.println("Table 4: " + seats[3] + " seats");
} catch (ArithmeticException e) {
System.out.println("Division by zero");
} catch (RuntimeException e) {
System.out.println("Runtime error");
} catch (Exception e) {
System.out.println("General error");
}
Answer

Try it

Find the bug

This program does not compile. Which line is the bug on?

Pick the line with the bug.

The idea

Checked exceptions and throws

The compiler makes you handle some exceptions. Here is a method that prints a receipt and waits for the printer with Thread.sleep (a pause in milliseconds):

static void printReceipt() {
System.out.println("Printing the receipt...");
Thread.sleep(300);
System.out.println("Done.");
}

The program does not compile: "unreported exception InterruptedException; must be caught or declared to be thrown". The pause can be interrupted from outside, and the compiler wants you to say what should happen then. You have two choices: catch the exception in the method, or declare it with throws and let the caller decide:

static void printReceipt() throws InterruptedException {
System.out.println("Printing the receipt...");
Thread.sleep(300);
System.out.println("Done.");
}
try {
printReceipt();
} catch (InterruptedException e) {
System.out.println("Interrupted.");
}
Output
Printing the receipt...
Done.
  • Checked exceptions are the subclasses of Exception that are not RuntimeException. They usually come from outside, from things beyond the program: a missing file, a dropped network connection, an interrupted pause.
  • Unchecked exceptions are RuntimeException and its subclasses. They are usually a mistake in the code or in the input: an index, division by zero, a wrong format. The compiler does not make you catch them.

You will meet a checked exception most often with files: IOException.

The idea

finally: always

The till's printer has to be freed after every receipt, or the next one will not print. Whatever happens, success or error:

static void printReceipt(String qtyText) {
System.out.println("The printer is busy.");
try {
int qty = Integer.parseInt(qtyText);
System.out.println("Coffee: " + qty + " x €2 = €" + qty * 2);
} catch (NumberFormatException e) {
System.out.println("Wrong quantity: " + qtyText);
} finally {
System.out.println("The printer is free.");
}
}
printReceipt("3");
printReceipt("three");
Output
The printer is busy.
Coffee: 3 x €2 = €6
The printer is free.
The printer is busy.
Wrong quantity: three
The printer is free.

finally runs always: when everything goes well, when the exception is caught, and even when none of these catch blocks catches it. In that last case finally runs, and the exception keeps going up to the next try that can catch it.

Why not just a line after the try/catch? Because that line is skipped if the exception is of a kind that catch does not catch, or if try has a return. finally is not skipped.

More precisely, if you are curious
  • You can also have try with finally and no catch: the exception is not caught, but the cleanup runs.
  • For resources that have to be closed, such as files and database connections, there is a shorter form: try (...) with the resource in the parentheses (try-with-resources). We will see it when we get to files. It closes the resource by itself, just as finally would.
  • finally does not run only if the whole program is stopped, for example with System.exit(0).

Try it

finally and return

What will the program print?

static String reserve(int guests) {
try {
if (guests > 6) {
return "No table for " + guests;
}
return "Table for " + guests;
} finally {
System.out.println("Logged the attempt.");
}
}
System.out.println(reserve(8));
Answer

Exercise

Programs with several catch blocks

Solve these in your editor. Do not print prompts.

1. Price per person. The prices are in the array { 120, 75, 300 }. Read a product number (from 1) and the number of people, and print the price per person with integer division. Catch three things: a product that does not exist, zero people, and everything else (then print the exception's message).

Input Output
2 and 3 Per person: €25
5 and 2 No such product.
1 and 0 The number of people cannot be 0.
1 and two Error: For input string: "two"

2. Calculator. Read a whole number, an operator (+, -, * or /) and a second whole number, each on its own line. Print the calculation. On text instead of a number say "Enter whole numbers.", on division by zero "Division by zero.", and on any other operator "Unknown operator: " followed by the operator.

Input
84
/
4
Output
84 / 4 = 21
Input
84
/
0
Output
Division by zero.

More tasks

  • The card terminal. The method pay(String amountText) prints "The terminal is connected.", then "Paid €X" or a message about wrong input, and in finally "The terminal is off." Call it with "25" and with "twenty".
  • Average grade without crashes. Read 5 lines with grades. Skip the ones that are not whole numbers (an exception) or are not from 2 to 6 (an if). Print the average with integer division. If no grade is valid, the division by zero throws: catch it and print "No valid grades."
  • Predict and check. Write a try with catch and finally, where each block prints a line. Predict the output on success, on a caught exception and on an uncaught one, then run it.
  • Pause. Write a method pause(int ms) that calls Thread.sleep(ms). Do it once with throws InterruptedException and once with try/catch inside. What does main have to do in each of the two cases?

Test

Check yourself

1. The exception matches two of the three catch blocks. Which one runs?
2. Does catch (RuntimeException e) catch an exception of type NumberFormatException?
3. Why does catch (Exception e) have to come last?
4. When does finally run?
5. Which exception is checked (the compiler makes you catch it or declare it with throws)?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·