Skip to content
wannacode

When something goes wrong

Problem

12a instead of 12

The concert box office asks how many tickets you want. A ticket is €15.

Main.java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("How many tickets? ");
int tickets = Integer.parseInt(in.nextLine());
System.out.println("Total: €" + tickets * 15);
}
}

With the input 12 the program says "Total: €180". But the customer is in a hurry and hits one letter too many:

The console
How many tickets? 12a
Exception in thread "main" java.lang.NumberFormatException: For input string: "12a"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:662)
at java.base/java.lang.Integer.parseInt(Integer.java:778)
at Main.main(Main.java:7)

The program stops. Instead of the total you get a long text, and the "Total" line is never reached. What does this text mean, and how do you keep the program from stopping because of one letter?

The idea

Exception

Integer.parseInt has to return a number. It cannot make a number out of "12a", and returning just any number would be a lie. So the method creates an object that describes the problem and throws it. This object is called an exception.

If nobody catches it, the program stops and shows what happened. This text is called a stack trace, and you read it from top to bottom:

  • The first line: the kind of exception and the message. NumberFormatException: For input string: "12a": the number has the wrong format, and here is the text.
  • The lines with "at": where it happened. This is the call stack from the recursion lesson, from the inside out. At the top is the method that threw the exception, and at the bottom is main.
  • Your line: the first "at" line that points to your file. Here: Main.java:7. The lines above it are in the code of Java, and you rarely need them.

The messages are in English because the language writes them, not you.

Try it

Find the bug

The program should print the last score from the test. It stops with this:

Error
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at Main.lastScore(Main.java:3)
at Main.main(Main.java:8)

Read the stack trace. Which line of the program is the bug on?

Pick the line with the bug.

The idea

try and catch

An exception can be caught. The code that might throw goes in try. What should happen on an error, you write in catch:

Scanner in = new Scanner(System.in);
System.out.print("How many tickets? ");
try {
int tickets = Integer.parseInt(in.nextLine());
System.out.println("Total: €" + tickets * 15);
} catch (NumberFormatException e) {
System.out.println("That is not a whole number.");
}
System.out.println("Thank you!");
Input
12a
Output
How many tickets? That is not a whole number.
Thank you!
  • In the parentheses of catch you write which kind of exception you catch.
  • If everything in try goes well, catch is skipped. With the input 12 the output is "Total: €180" and "Thank you!".
  • After catch the program continues on. It no longer stops.

Scanner in = new Scanner(System.in);
System.out.print("How many tickets? ");
try {
int tickets = Integer.parseInt(in.nextLine());
System.out.println("Total: €" + tickets * 15);
} catch (NumberFormatException e) {
System.out.println("That is not a whole number.");
}
System.out.println("Thank you!");
Step by step, in words
  1. The program asks how many tickets. You type "12a".
  2. In try: parseInt tries to make a number out of "12a".
  3. It cannot. The method throws NumberFormatException.
  4. Execution jumps straight into catch. The "Total" line is skipped.
  5. catch is for exactly this kind of error: it prints the message for the customer.
  6. After catch the program continues. It does not stop.
More precisely, if you are curious
  • A variable declared in try (here tickets) exists only until the closing brace of try. If you need it after the block too, declare it before try.
  • In Java the name is required: catch (NumberFormatException e), even if you do not use it. By habit it is e.

Try it

Which lines run?

What will the program print?

System.out.println("Start");
try {
System.out.println("Reading");
int seats = Integer.parseInt("ten");
System.out.println("Got " + seats);
} catch (NumberFormatException e) {
System.out.println("Bad input");
}
System.out.println("End");
Answer

The idea

What the exception says

The exception is an object, and e in catch (NumberFormatException e) is the variable that points to it. The object has a way to give you the message: e.getMessage().

Scanner in = new Scanner(System.in);
try {
int tickets = Integer.parseInt(in.nextLine());
System.out.println("Total: €" + tickets * 15);
} catch (NumberFormatException e) {
System.out.println("Error: " + e.getMessage());
}
Input
12a
Output
Error: For input string: "12a"

The message is useful to you when you are looking for the bug. To the customer you usually show your own text, in their language, such as "That is not a whole number."

The idea

Ask until it is right

The customer made a mistake. You do not have to stop. Ask again:

Scanner in = new Scanner(System.in);
int tickets;
while (true) {
System.out.print("How many tickets? ");
try {
tickets = Integer.parseInt(in.nextLine());
break;
} catch (NumberFormatException e) {
System.out.println("Enter a whole number, for example 3.");
}
}
System.out.println("Total: €" + tickets * 15);
Input
12a
twelve
12
Output
How many tickets? Enter a whole number, for example 3.
How many tickets? Enter a whole number, for example 3.
How many tickets? Total: €180

while (true) keeps looping until break stops it. And break is reached only if parseInt succeeds. On an error, execution jumps into catch, and after it the loop starts over and asks again.

More precisely, if you are curious
  • Java has no TryParse. Catching NumberFormatException is the usual way. Scanner also has hasNextInt(), which checks whether a whole number comes next, without reading it.

Try it

Division by zero

Not every exception comes from the input. The average order value is the revenue divided by the number of orders. But on the first day there are no orders. With whole numbers, revenue / orders stops the program:

Error
Exception in thread "main" java.lang.ArithmeticException: / by zero

What about decimal numbers?

What will the program print?

int revenue = 90;
int orders = 0;
double average = (double) revenue / orders;
System.out.println(average);
Answer
More precisely, if you are curious
  • Whole numbers have no value for infinity, so all that is left there is the exception. For decimal numbers, the rules come from the IEEE 754 standard for floating point numbers, which every language follows.

Exercise

Programs that do not stop

Solve these in your editor. Do not print prompts, so your output matches the sample.

1. Text to number. Write a method toNumber(String text) that returns the text as a double. Read two lines. For each, print the number or a message that it is not a number. Catch the exception in main.

Input
123.45
123.abc
Output
The number is: 123.45
Error: 123.abc is not a number.

2. No such product. The prices are in the array { 120, 75, 300, 45, 89 }. Read a product number from 1 to 5 and print its price. If the number is outside the array, catch the exception and say so. With the input 2 the output is Price: €75.

Input
7
Output
There is no product number 7.

3. Average order. Read the revenue and the number of orders (whole numbers) and print the average with integer division. If there are no orders, catch the exception. With the input 900 and 4 the output is Average: €225.

Input
90
0
Output
No orders yet.

More tasks

  • Age, until it is right. Ask for an age until the input is a whole number from 0 to 120. For text like "twenty" say "That is not a number.", and for 150 say "The age must be from 0 to 120." One is an exception, the other is an if.
  • Sum of the valid ones. Read 5 lines. Add up the ones that are whole numbers and count the skipped ones: with the input 10, abc, 5, 7.5, 3 the output is Sum: 18, skipped: 2.
  • Division on demand. Read two whole numbers and print the quotient. On text instead of a number and on division by zero, the program does not stop. It asks again for both numbers.

Test

Check yourself

1. What is an exception?
2. The program stopped with a long error text. Where do you start reading?
3. A try has four lines. The second one throws an exception, and catch catches it. What happens to the third and the fourth?
4. What happens with int x = 90 / orders; when orders = 0?
5. Does catch (NumberFormatException e) catch the error from scores[10] in an array of 5 elements?

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