Learn Java

Lesson 45Phase 5: Errors, files and the standard library

Scanner and console applications

Reading numbers and lines from the keyboard, building a small interactive program, and common Scanner traps.

By Updated 55 min

  • Scanner
  • System.in
  • nextInt
  • nextLine
  • input buffer
  • interactive loop

Every program you have written so far has done all the talking. It prints, it computes, it prints again, and it never once stops to ask you anything. Many real tools hold a conversation instead: they ask, you answer, they react. This lesson gives your programs ears, so they can read what a person types at the keyboard.

By the end of this lesson
  • Create a Scanner that reads from the keyboard, and explain what System.in is.
  • Read a number with nextInt or nextDouble, one word with next, and a whole line with nextLine.
  • Build a small interactive program that asks for a name and an age and greets the person.
  • Check input with hasNextInt before reading it, so a typo does not crash the program.
  • Recognise and fix the classic nextInt-then-nextLine trap that eats your input.
  • Read in a loop until the person types a sentinel value, or until the input runs out.
From before
You will lean on packages and imports right away, because Scanner lives in java.util and you must import it. You also need loops for the interactive loops, if-else to react to what was typed, and Integer.parseInt from wrapper classes to turn text into a number.
Typing into a program on this page
Every program on this page runs. Under its code is a box labelled “Keyboard input”. Each line in the box is one line the person types, ending with Enter, and each time the program reads the keyboard it takes what it needs from those lines. Change the lines and run again to try your own answers. The console shows the typed text in italics, right after the prompt, where it would appear in a terminal.

From a monologue to a conversation#

Until now, output went out through System.out. There is a matching door for input called System.in. Think of System.out as the program's mouth and System.in as its ear. On its own, System.in is awkward to use: it hands over raw bytes, one at a time, with no idea of numbers or words. The Scanner class wraps it and does that work for you, reading a whole number, a word or a line at a time.

A Scanner is an object. String lives in java.lang, which every program can use without an import, but Scanner lives in the package java.util, so you import it first, as you saw in packages and imports.

Greet.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("What is your name? ");
8 String name = sc.nextLine();
9
10 System.out.println("Hello, " + name);
11 }
12}
Prints
›What is your name? AishaHello, Aisha

Read it from top to bottom. The import line brings the name Scanner into scope so you can write it plainly. Then new Scanner(System.in) builds a scanner and points it at the keyboard. After that, sc.nextLine() waits until the person types something and presses Enter. Whatever they typed comes back as a String, which the program stores in name and then prints. Run it, then put your own name in the box and run it again.

print, not println, for a prompt
The prompt uses System.out.print, with no ln. That keeps the cursor on the same line, so the person types their answer right after the question mark instead of on a fresh line below it.

The reading methods, one job each#

A scanner has a small family of read methods, and each one reads a different shape of input. Picking the right one is most of the skill. These are the four you will use most:

  • nextInt() reads the next whole number and gives you an int.
  • nextDouble() reads the next number that may have a decimal point and gives you a double.
  • next() reads a single token: one run of non-space characters, one word.
  • nextLine() reads everything up to the end of the current line, spaces and all.

A scanner splits what you type into pieces at the whitespace: spaces, tabs and line breaks. Each piece is a token. If you type red green blue, that is three tokens. next() takes exactly one of them and stops at the space. nextLine() takes the rest of the line as one string, spaces included.

Tokens.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("Type three words: ");
8 String word = sc.next();
9
10 System.out.println("First word only: " + word);
11 }
12}
Prints
›Type three words: red green blueFirst word only: red

The person typed three words, but next() kept only the first, red. The scanner keeps typed text that has not been read yet in its input buffer, and green blue is still sitting there, waiting for a read call that never comes. That leftover is harmless here. Later on this page, leftover text in the buffer is the cause of the most common Scanner bug.

Method
Reads
nextInt()
One whole number, for example 42, as an int.
nextDouble()
One number that may have a decimal point, for example 3.5, as a double.
next()
One word. It stops at the first space.
nextLine()
The rest of the current line, spaces included, as a String.
Quick check
The person types Ada Lovelace and presses Enter. Which call gives you the string "Ada Lovelace", with the space?
Coming from Python?
Python's input() hands you the whole line as a string, and you convert it yourself. A Scanner has a method for each shape, so nextInt() gives you an int with no conversion step, as long as you pick the method that matches what the person will type. The closest match to input() is IO.readln, from Java 25, near the end of this page.

A first interactive program#

Here is a program that asks two questions and reacts. It asks for a name and an age, then greets the person and says how old they will be next year. Almost every console tool has this shape: prompt, read, prompt, read, then compute and respond.

Greeter.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("What is your name? ");
8 String name = sc.next();
9
10 System.out.print("How old are you? ");
11 int age = sc.nextInt();
12
13 int nextYear = age + 1;
14 System.out.println("Hello, " + name + ". Next year you will be " + nextYear + ".");
15 }
16}
Prints
›What is your name? Aisha
›How old are you? 20Hello, Aisha. Next year you will be 21.

Follow the conversation. The program prints the first prompt and reads. The first line of input is Aisha, so next() returns "Aisha". The program prints the second prompt and reads again. The next line is 20, so nextInt() returns the int 20. With both values in hand, it adds one and prints the greeting. Because age is a real int, the + 1 is arithmetic, not joining text.

When the input is not a number#

People make typos. Suppose someone types twenty at the How old are you? prompt. nextInt() cannot turn twenty into an int, so it throws an exception, the kind of error report you met in reading errors and debugging, and the program stops.

BadAge.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("How old are you? ");
8 int age = sc.nextInt();
9
10 System.out.println("Next year you will be " + (age + 1) + ".");
11 }
12}
Prints
›How old are you? twentyException in thread "main" java.util.InputMismatchException
! at Main.main(Main.java:8)
Stops on line 8

InputMismatchException

The next piece of input did not match the type that was asked for.

The program stops on line 8 with an InputMismatchException: the next token did not match the type the program asked for. The last line of the report, at Main.main(Main.java:8), points at the line that asked for the number. In a terminal, Java's report also lists a few lines from inside the Scanner class itself, above that one.

Now change the input to 3000000000 and run it again. That token looks like a whole number, but it is too big for an int, so this time the report adds the detail For input string: "3000000000".

Check before you read: hasNextInt#

A scanner can look at the next token without reading it. hasNextInt() answers one question: is the next token a whole number? It returns true or false and leaves the token where it is. That makes a loop that keeps asking until the answer is usable:

AskAgain.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("How old are you? ");
8 while (!sc.hasNextInt()) {
9 String wrong = sc.next();
10 System.out.print(wrong + " is not a whole number. Try again: ");
11 }
12 int age = sc.nextInt();
13
14 System.out.println("Next year you will be " + (age + 1) + ".");
15 }
16}
Prints
›How old are you? twenty
›twenty is not a whole number. Try again: 20.5
›20.5 is not a whole number. Try again: 20Next year you will be 21.

With this input the loop body runs twice. twenty is not a whole number, so the loop throws it away with next() and asks again. Neither is 20.5. Then 20 arrives, hasNextInt() returns true, the loop ends, and nextInt() reads it. The next() inside the loop matters: hasNextInt() never moves past a token, so without it the loop would look at twenty forever.

Its relatives work the same way. hasNextDouble() checks for a number that may have a decimal point, hasNext() checks for any token at all, and hasNextLine() checks for another line. Each one answers yes or no and reads nothing.

Quick check
The next token in the input is seven. What does sc.hasNextInt() do?
Catching the error instead
Another way is to let nextInt() throw, catch the InputMismatchException, and ask again. That uses try and catch, which exception handling teaches. hasNextInt() does the job with nothing new.

The classic trap: nextInt then nextLine#

Here is the most common bug a beginner hits with Scanner, and almost everyone hits it once. You read a number, then want to read a full line of text afterward. The obvious code looks right and is wrong.

Broken.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("Enter your age: ");
8 int age = sc.nextInt();
9
10 System.out.print("Enter your full name: ");
11 String fullName = sc.nextLine();
12
13 System.out.println("Hello, '" + fullName + "' (age " + age + ")");
14 }
15}
Prints
›Enter your age: 20
›Enter your full name: Hello, '' (age 20)

Run it and look at the console. The program never gave the person a chance to type a name. It printed the second prompt and then the greeting straight away, with fullName empty: the two quote marks have nothing between them. The second line of input, Aisha Khan, was never read. Step through it and stop on line 11, where the narration says what happened.

nextInt leaves the Enter key behind
When you type 20 and press Enter, two things land in the buffer: the characters 20 and an invisible line break from the Enter key, which Java writes as \n. nextInt() reads the 20 and stops. It leaves the line break sitting there, unread. The next nextLine() reads from the current spot to the end of the line, finds only that leftover line break, and returns an empty string at once, without waiting for the person.
Predict the outputLeftover.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6 int count = sc.nextInt();
7 String item = sc.nextLine();
8 String next = sc.nextLine();
9 System.out.println(count + " [" + item + "] [" + next + "]");
10 }
11}

The keyboard input is two lines: 3, then blue pens. What does the program print?

The first nextLine() gets the empty rest of the line that held 3. The second one starts on a fresh line and gets blue pens. So the output is 3 [] [blue pens], and that extra call is exactly the fix.

The fix: eat the leftover line break#

The cure is one extra line. After the nextInt(), call sc.nextLine() once on its own and ignore what it returns. That spare call swallows the stranded line break, so the next nextLine() starts at the beginning of a fresh line.

Fixed.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("Enter your age: ");
8 int age = sc.nextInt();
9
10 sc.nextLine(); // consume the leftover line break after the number
11
12 System.out.print("Enter your full name: ");
13 String fullName = sc.nextLine();
14
15 System.out.println("Hello, '" + fullName + "' (age " + age + ")");
16 }
17}
Prints
›Enter your age: 20
›Enter your full name: Aisha KhanHello, 'Aisha Khan' (age 20)

One throwaway sc.nextLine() between the number read and the line read is the whole fix. The name has a space in it, so nextLine() was the right tool, and with the leftover line break gone it captures Aisha Khan in full.

Key idea

Reading a number with nextInt or nextDouble leaves the Enter line break in the buffer. If a nextLine comes next, add a throwaway sc.nextLine() between them to clear it.

The other fix: read only whole lines#

The second way out is to never mix the two kinds of read. Read every answer as a whole line with nextLine(), and turn the lines that hold numbers into numbers yourself with Integer.parseInt. Each nextLine() takes its whole line, line break included, so nothing is ever left behind.

LinesOnly.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("Enter your age: ");
8 int age = Integer.parseInt(sc.nextLine().trim());
9
10 System.out.print("Enter your full name: ");
11 String fullName = sc.nextLine();
12
13 System.out.println("Hello, '" + fullName + "' (age " + age + ")");
14 }
15}
Prints
›Enter your age: 20
›Enter your full name: Aisha KhanHello, 'Aisha Khan' (age 20)

The trim() removes any spaces around the number before it is parsed, because parseInt refuses a space in front of the digits.

Pick one habit
If a program mixes number reads and line reads, choose one habit and use it everywhere: either clear the buffer with a spare sc.nextLine() after every nextInt or nextDouble, or read everything with nextLine() and convert the numbers yourself.
Quick check
int n = sc.nextInt(); has just read 7 from a line the person ended with Enter. Which call comes back at once with an empty string?
ExerciseOrder.java
A shop program reads a quantity, then a product name that may contain spaces. Right now the product comes out empty. Fix the program so that the keyboard input 3 and blue pens prints 3 x blue pens.

Reading in a loop until a sentinel#

One read is a single question. A real tool keeps asking until you are done. The usual pattern is to read over and over inside a loop, and stop when the person types a special agreed value that means “I am finished”. That value is called a sentinel, like a guard standing at the exit.

The program below keeps reading numbers and adding them to a running total. The sentinel is 0. As soon as the person types 0, the loop ends and the program reports the sum. Every other number goes into the total.

Adder.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6 int total = 0;
7
8 System.out.print("Enter a number (0 to finish): ");
9 int n = sc.nextInt();
10
11 while (n != 0) {
12 total = total + n;
13 System.out.print("Enter a number (0 to finish): ");
14 n = sc.nextInt();
15 }
16
17 System.out.println("Total: " + total);
18 }
19}
Prints
›Enter a number (0 to finish): 5
›Enter a number (0 to finish): 12
›Enter a number (0 to finish): 3
›Enter a number (0 to finish): 0Total: 20

Walk through the run with the code beside it. The program reads one number before the loop, called the priming read, so the while condition has something to test. The first number is 5, which is not 0, so the loop body runs: it adds 5 to total, prompts, and reads again. The same happens for 12 and 3. Then 0 arrives: the condition n != 0 is now false, the loop stops, and the program prints the sum of 5, 12 and 3, which is Total: 20. The sentinel itself is never added, because the program reads it, tests it, and leaves before adding.

  1. 1Read once before the loop. This is the priming read that gives the condition a value to check.
  2. 2While the value is not the sentinel, do the work, then read the next value at the bottom of the loop.
  3. 3When the sentinel arrives, the condition fails and the loop ends without processing it.
Key idea

A sentinel loop reads once before the loop and again at the end of every pass, so the condition always tests the newest value and the sentinel itself is never processed.

A sentinel must be a value that is never real data
This program uses 0 because adding zero changes nothing, so it is safe to reserve as the stop signal. If 0 were a number you really wanted to total, you would need a different sentinel, perhaps a negative number, or a word such as done. The rule: pick a value the real data can never take.
Put the lines in orderWords.java
This program counts the words a person types before the word done. The keyboard input is apple pear on one line and plum done on the next. Put the lines in order so that it prints 3 words before done.

Tap a line, then tap where it should go. Or use the arrows.

Quick check
A program totals the prices of the items in a shopping basket, read with nextInt(). Some items are free, with a price of 0. Which sentinel is safe?

Stop when the input runs out#

Sometimes there is no sentinel at all, and the program reads until there is nothing left. hasNextInt() returns false at the end of the input, and also when the next token is not a whole number, so it makes a natural loop condition:

UntilEnd.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6 int total = 0;
7 int count = 0;
8
9 while (sc.hasNextInt()) {
10 total = total + sc.nextInt();
11 count++;
12 }
13
14 System.out.println(count + " numbers, total " + total);
15 }
16}
Prints
›5 12
›33 numbers, total 20

This prints 3 numbers, total 20. The input has 5 and 12 on one line and 3 on the next, and that makes no difference, because nextInt() skips spaces and line breaks alike. On this page the input ends where the box ends. In a terminal, the person signals the end by pressing Ctrl+D on macOS and Linux, or Ctrl+Z and then Enter on Windows. A file always has an end, and the next lesson reads files with this same kind of loop.

ExerciseHighest.java
A quiz app reads scores from 0 to 100, as many as the person types, until the input runs out. Finish the program so that it prints the highest score. For the input 72, 95, 68 it should print Highest: 95.

Putting it together: a tiny menu#

Here is the shape of a complete little console app: a loop, a sentinel, and a branch on what was typed. It reads a command word each time and acts on it, stopping when the person types quit. Every entry is a single word read with next(), so there is no line-break trap to worry about.

Menu.java
1import java.util.Scanner;
2
3public class Main {
4 public static void main(String[] args) {
5 Scanner sc = new Scanner(System.in);
6
7 System.out.print("Command (hello / bye / quit): ");
8 String cmd = sc.next();
9
10 while (!cmd.equals("quit")) {
11 if (cmd.equals("hello")) {
12 System.out.println("The program says hi.");
13 } else if (cmd.equals("bye")) {
14 System.out.println("The program waves goodbye.");
15 } else {
16 System.out.println("Unknown command: " + cmd);
17 }
18 System.out.print("Command (hello / bye / quit): ");
19 cmd = sc.next();
20 }
21
22 System.out.println("Shutting down.");
23 }
24}
Prints
›Command (hello / bye / quit): hello
›The program says hi.
›Command (hello / bye / quit): dance
›Unknown command: dance
›Command (hello / bye / quit): bye
›The program waves goodbye.
›Command (hello / bye / quit): quitShutting down.

This is the same priming-read pattern as the adder, with a word as the sentinel and an if-else chain in the middle. dance is not a command, so it lands in the final else. The program compares strings with cmd.equals("quit"), never with ==, because == asks whether two variables point at the very same object while equals compares the text. That distinction was the heart of references and equality.

One scanner for the whole program
Create the Scanner once, at the start of main, and pass it to any method that needs to read. Two scanners on System.in can fight over the input: the first one may read ahead and keep text that the second never sees. Calling close() on a scanner over System.in also closes System.in itself, so nothing can read the keyboard after that. A scanner on System.in can stay open until the program ends.

Two other ways to read a line#

Java 25 added a small class called IO with methods for the console. IO.readln(prompt) prints the prompt, then reads one whole line and returns it as a String. IO lives in java.lang, so it needs no import.

Readln.java
1public class Main {
2 public static void main(String[] args) {
3 String name = IO.readln("What is your name? ");
4 int age = Integer.parseInt(IO.readln("How old are you? "));
5
6 IO.println("Hello, " + name + ". Next year you will be " + (age + 1) + ".");
7 }
8}
Prints
›What is your name? Aisha Khan
›How old are you? 20Hello, Aisha Khan. Next year you will be 21.

IO.readln always gives you text, so the age goes through Integer.parseInt. There is no trap here, because every call reads exactly one whole line. Read the keyboard with either IO.readln or a Scanner in one program, not both: the documentation warns that after the first readln call, any other use of System.in gives unspecified results.

You will also see older code read the keyboard with a BufferedReader wrapped around System.in. Its readLine() method returns one whole line, much like IO.readln. BufferedReader comes up properly in the next lesson, where it reads files.

Where this leads next
A console program can only talk to whoever is at the keyboard right now, and it forgets everything when it ends. To remember answers between runs, a program writes them to a file and reads them back later. Reading a file works much like reading the keyboard, line by line, and it is the subject of reading files.

Try it

Answer each one in your head or on paper first, then open the answer.

1
What two things does the line Scanner sc = new Scanner(System.in); set up, and what does System.in stand for?
2
The person types hello world and presses Enter. The program calls sc.next(). What string comes back, and what is left unread?
3
Explain in one or two sentences why a nextLine() placed right after a nextInt() often comes back empty.
4
A program reads an age with nextInt() and then a city with next(). Does it need a throwaway nextLine() between them?
5
The keyboard input for the adder is 4, 4 and 0, one per line. What does it print, and how many times does the loop body run?
6
In AskAgain.java, the keyboard input is twenty years on one line and 20 on the next. How many “is not a whole number” messages appear?

Practice

Work through these on your own. Each one builds on this page.

1
Write a console program that asks for a person's first name with next(), then their favourite quote with nextLine(), then prints them together. Make it work even though a line read follows a word read. To test it, open any program on this page full screen, replace its code with yours, and type your answers in the keyboard input box.
2
Extend the adder so it also reports how many numbers were entered and their average as a double. Do not count or include the 0.
3
Ask for a month number and keep asking until the person types a whole number from 1 to 12. Use hasNextInt() for words and decimals and an if for numbers out of range, then print the month's number back.
4
Build a small interactive program that reads a command word in a loop: add reads one number and adds it to a running total, show prints the current total, and quit stops.
5
In your own words, write one short paragraph explaining the difference between next() and nextLine(), and give one situation where choosing the wrong one would change what your program reads.

Further reading#

Spotted a mistake, or a part that did not make sense? Report it by email