Command Palette

Search for a command to run...

PHASE 1Beginner Java 5+ ~31 min· topic 13 of 14

Topic 1.13

Reading Keyboard Input with Scanner

In one line

java.util.Scanner reads text from the keyboard (or from a String or file) and splits it into tokens separated by whitespace, converting each one with nextInt, nextDouble, next or nextLine. Check with hasNextInt before you read, and watch out for the leftover line break after nextInt.

Think of it like this

A ticket clerk reading a queue of words. The clerk takes the next word in the queue each time you ask: 'give me a number' takes the next word and checks that it's a number; 'give me the rest of the line' takes everything up to the end of the current line. If you ask for a number and the next word is hello, the clerk refuses and raises an alarm. Scanner is that clerk; the queue is the text the user typed.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Input
Data that comes into a program from outside: typed on a keyboard, read from a file, or received over a network.
Standard input
The program's default input stream, System.in. In a terminal it is the keyboard; it can also be fed from a file.
Scanner
A class in java.util that reads text and hands it to you piece by piece, converting pieces to numbers when asked.
Token
One piece of input between delimiters, such as Asha or 42 in Asha 42.
Delimiter
The separator between tokens. For Scanner it is any whitespace by default: spaces, tabs and line breaks.
Whitespace
Characters you can't see but that make space: the space bar, tab and the line break from Enter.
Blocking
Waiting. A blocking call pauses the program until the data it needs arrives.
Import
A line at the top of a file, like import java.util.Scanner;, that lets you use a class from another package by its short name.
Exception
An error object Java throws while the program runs. If nothing catches it, the program stops and prints it (Phase 7).

Step by step

01Your first interactive program

Three lines do the work: the import, creating the Scanner, and asking it for values. print (not println) shows the question so the cursor waits on the same line.

This program needs a real keyboard, so run it in a terminal on your own machine. The examples further down use a fixed String instead, so they can run right here.

Main.javawhole filejava
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Your name: ");
        String name = in.nextLine();
        System.out.print("Your age: ");
        int age = in.nextInt();
        System.out.print("Your height in metres: ");
        double height = in.nextDouble();
        System.out.println();
        System.out.println("Hello, " + name + "!");
        System.out.println("In 10 years you will be " + (age + 10) + ".");
        System.out.printf("Your height is %.2f m.%n", height);
    }
}
terminal
$ java Main.java
── expected output ──
Your name: Asha Kumar
Your age: 12
Your height in metres: 1.45
 
Hello, Asha Kumar!
In 10 years you will be 22.
Your height is 1.45 m.

02What happens when you type

While you type, the characters sit in the terminal, not in your program. Only when you press Enter does the terminal send the whole line, including the line break, to the program's standard input.

Inside, Scanner keeps a buffer (a holding area) of characters it has received but not yet handed out. Each next... call takes from the buffer; if the buffer doesn't hold a complete token yet, the call blocks and waits for more input.

What happens when you typediagram
Rendering diagram…

03Tokens: whitespace separates, and line breaks are whitespace

Because line breaks count as whitespace, nextInt() doesn't care whether the user types 5 8 on one line or 5, Enter, 8 on two lines. Both give two tokens.

next() returns one token, so it can't read a full name with a space: for Asha Kumar it returns just Asha. Use nextLine() when spaces are part of the value.

04The nextInt then nextLine trap

Suppose the input is 25 Enter Asha Kumar Enter. nextInt() reads 25 and stops right before the line break. nextLine() then reads 'the rest of the current line', which is nothing, and returns "".

Fix 1: after nextInt(), call in.nextLine(); once and ignore the result. Fix 2 (more robust): read every value with nextLine() and convert it yourself with Integer.parseInt(line.strip()). Then each read takes exactly one line, and there's never a leftover.

The nextInt then nextLine trapdiagram
Rendering diagram…

05Check before you read

Users type mistakes. hasNextInt() answers 'is the next token a valid int?' without consuming it. If not, read it with next() to discard it, tell the user, and try again.

Note that after InputMismatchException the bad token is still in the buffer. A loop that just retries nextInt() will fail on the same token forever. Always consume it with next() or nextLine().

Main.javawhole filejava
System.out.print("Enter a whole number: ");
while (!in.hasNextInt()) {
    String bad = in.next();          // throw the bad token away
    System.out.print(bad + " is not a whole number, try again: ");
}
int n = in.nextInt();

06Locale and number formats

nextDouble() follows the Scanner's locale, which starts as the machine's default. A German locale reads 1,45 as one point four five and doesn't accept 1.45 as a double at all. Grouping separators are accepted too: with Locale.US, nextInt() reads 1,000 as 1000.

When your input has a fixed format (a file, test data, a contest), set it once: in.useLocale(Locale.US);.

07One Scanner, and don't close the keyboard

Creating a second new Scanner(System.in) in another method is a common source of 'lost' input: the first Scanner may already have pulled characters into its buffer, and the second one never sees them. Create one Scanner and pass it where it's needed.

in.close() closes the underlying stream too. For System.in that means the keyboard is gone for the rest of the program, and a later read throws NoSuchElementException. Close Scanners over files (with try-with-resources, Topic 7.6); for a Scanner over System.in it's fine to leave it open, and the operating system cleans up when the program ends.

Try it yourself

  1. 1

    Run the keyboard program on your machine

    Copy the first walkthrough program into Main.java on your computer, compile it with javac Main.java and run java Main in a terminal. Type your own name, age and height. Then run it again and type twelve for the age, and read the exception.

    terminal
    $ java Main
    ── expected output ──
    Your name: Asha Kumar
    Your age: twelve
    Exception in thread "main" java.util.InputMismatchException
    at java.base/java.util.Scanner.throwFor(Scanner.java:947)
    at java.base/java.util.Scanner.next(Scanner.java:1602)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2267)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2221)
    at Main.main(Main.java:9)
  2. 2

    Change the fake keyboard

    In 'Read numbers until the input ends', change the String to "10 20 oops 30". Predict the count and sum before running. The loop stops at oops because hasNextInt() is false there, so you get count 2 and sum 30; 30 is never read.

  3. 3

    Reproduce the trap

    In the trap example, delete the second name = in.nextLine(); and its print. Now the program reports an empty name, exactly what happens to a real user who typed their age and then never got asked for their name.

Code & diagrams

Reading tokens from a fixed String New tab

With `new Scanner(System.in)` instead of the String, the same code reads from the keyboard. `nextDouble` uses your locale's decimal separator; on an English-language setup that's a dot.

Sign in to run this example in your browser.

Expected output

name:   Asha
age:    12 (next year 13)
height: 1.45
member: true
more?   false
Read numbers until the input ends New tab

`while` loops are covered in Topic 2.5; here it just repeats as long as another whole number is waiting.

Sign in to run this example in your browser.

Expected output

count:   4
sum:     100
average: 25.0
The nextInt then nextLine trap, and the fix New tab
Sign in to run this example in your browser.

Expected output

age=25 name=[]
name=[Asha Kumar]
age2=25 name2=[Asha Kumar]
Skip bad tokens, and fix the locale New tab
Sign in to run this example in your browser.

Expected output

number:  12
skipped: abc
number:  7
skipped: x9
number:  30
US double: 1.45
US int:    1000
DE double: 1.45
Line by line with hasNextLine New tab
Sign in to run this example in your browser.

Expected output

1: 2 x milk
2: 1 x bread
3: 12 x eggs

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Type a word where a number is expected

Run the age program and type twelve.

Main.javawhole filejava
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("How old are you? ");
        int age = in.nextInt();
        System.out.println("Next year you will be " + (age + 1));
    }
}
terminal
$ java Main
── what you'll see ──
How old are you? twelve
Exception in thread "main" java.util.InputMismatchException
at java.base/java.util.Scanner.throwFor(Scanner.java:947)
at java.base/java.util.Scanner.next(Scanner.java:1602)
at java.base/java.util.Scanner.nextInt(Scanner.java:2267)
at java.base/java.util.Scanner.nextInt(Scanner.java:2221)
at Main.main(Main.java:7)
From JDK 21. The line numbers inside `Scanner.java` differ between JDK versions.

Break #2

Forget the import

Delete import java.util.Scanner;.

terminal
$ javac Main.java
── what you'll see ──
Main.java:3: error: cannot find symbol
Scanner in = new Scanner(System.in);
^
symbol: class Scanner
location: class Main
Main.java:3: error: cannot find symbol
Scanner in = new Scanner(System.in);
^
symbol: class Scanner
location: class Main
2 errors

Break #3

Read more than there is

Scan the String "5 8" and call nextInt() three times.

Main.javawhole filejava
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner("5 8");
        int a = in.nextInt();
        int b = in.nextInt();
        int c = in.nextInt();
        System.out.println(a + b + c);
    }
}
terminal
$ javac Main.java
java Main
── what you'll see ──
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.Scanner.throwFor(Scanner.java:945)
at java.base/java.util.Scanner.next(Scanner.java:1602)
at java.base/java.util.Scanner.nextInt(Scanner.java:2267)
at java.base/java.util.Scanner.nextInt(Scanner.java:2221)
at Main.main(Main.java:8)

Myth vs fact

Myth

nextInt() reads the whole line the user typed.

Fact

It reads one token and stops right before the line break. That leftover break is what makes a following nextLine() return empty text.

Myth

next() reads the user's full name.

Fact

next() reads one token, so Asha Kumar gives Asha. Use nextLine() when the value can contain spaces.

Myth

Every Scanner should be closed.

Fact

Close Scanners over files. Closing a Scanner over System.in closes the keyboard stream for the whole program; usually you leave it open.

Myth

Scanner is fine for any amount of input.

Fact

It's convenient but slow: it matches regular expressions for every token. For hundreds of thousands of numbers, BufferedReader with manual parsing is many times faster.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Scanner is built on regular expressions (java.util.regex, Topic 6.7): hasNextInt() matches the buffer against a locale-specific integer pattern that allows a sign and grouping separators. useDelimiter(",") swaps the whitespace delimiter for any pattern, which makes simple CSV-like input easy.

  • ▸

    Scanner reads its source in chunks of 1024 characters into an internal buffer. That is why two Scanners on System.in misbehave: the first may have read characters the second will never see.

  • ▸

    Scanner hides I/O errors: methods don't throw IOException; instead in.ioException() returns the last one. BufferedReader.readLine() reports them directly, another reason servers and file-processing code prefer it.

  • ▸

    System.console() returns a Console with readLine and readPassword (which doesn't echo the characters), but it is null when there is no interactive terminal, for example in IDE consoles or when input is redirected. Java 25 added java.lang.IO with IO.readln(prompt) for simple programs, alongside compact source files (Topic 0.3).

Remember this

  1. 1

    Create one with Scanner in = new Scanner(System.in); after import java.util.Scanner;. System.in is the program's standard input, an InputStream of raw bytes from the keyboard. Scanner turns those bytes into characters and the characters into tokens: pieces of text separated by whitespace (spaces, tabs, line breaks), which is Scanner's default delimiter.

  2. 2

    Token methods: next() returns the next token as a String, nextInt(), nextLong(), nextDouble() and nextBoolean() read the next token and convert it. They skip any whitespace first, so 42 reads as 42, and numbers on one line or on separate lines work the same way. nextLine() is different: it returns everything up to the end of the current line (without the line break) and moves past it.

  3. 3

    Every next... call blocks: the program waits until the user has typed enough and pressed Enter. If the token doesn't match, nextInt throws InputMismatchException and leaves the bad token in place; if the input has ended, it throws NoSuchElementException. The hasNextInt(), hasNextDouble(), hasNext() and hasNextLine() methods look ahead without consuming anything, so you can check first and react.

  4. 4

    The classic trap: nextInt() reads 25 but leaves the Enter key's line break behind. A following nextLine() finds that empty rest-of-line and returns "" immediately, so the user never gets to type their name. Fix it by calling nextLine() once to throw the rest away, or by reading every line with nextLine() and converting with Integer.parseInt(line.strip()) (Topic 1.6).

  5. 5

    Numbers are read using the default locale: on a German system nextDouble() expects 1,45, not 1.45. Call in.useLocale(Locale.US) when the input format is fixed. Create one Scanner for System.in and reuse it; closing it also closes System.in, after which no part of the program can read the keyboard again.

  6. 6

    Scanner can read from other sources too: new Scanner("12 34") scans a fixed String (perfect for testing, and what this page's runnable examples do, because the browser has no keyboard), and new Scanner(Path.of("data.txt")) scans a file (Phase 12). For very large inputs, such as programming contests, BufferedReader is much faster (see the DSA course at /dsa).

Explain it without notes

01

What is a token, and how does nextInt() decide where one ends?

02

Explain why nextLine() after nextInt() returns an empty String, and give two fixes.

03

What is the difference between hasNextInt() and nextInt(), and why does a retry loop need next()?

04

Why should a program create only one Scanner for System.in, and why not close it?

Practice

01

Using new Scanner("7 3"), read two integers and print their sum, difference, product and integer quotient on separate labelled lines.

02

Using new Scanner("Meera\n14\n"), read a name with nextLine() and an age, and print Meera will be 18 in 4 years. Read the age the robust way (whole line plus parseInt).

03

Using new Scanner("5 -2 abc 9 0 4.5 3"), add up only the valid integers and print how many tokens were skipped.

Trade-offs

  • ↔

    Scanner's typed methods (nextInt, nextDouble) are convenient and validate input, but they are slow and their mix with nextLine is error-prone; reading whole lines and parsing them yourself is more predictable.

  • ↔

    BufferedReader is fast and reports I/O errors, but gives you only lines; you split and convert them yourself.

  • ↔

    Command-line arguments (the args array of main) suit values known when the program starts and scripts; interactive input suits programs that talk to a person.

Done when you can

  • I can create a Scanner for the keyboard and for a fixed String, with the right import.

  • I can read Strings, ints, doubles and booleans and explain what a token is.

  • I can explain and fix the nextInt then nextLine trap.

  • I validate input with hasNextInt and discard bad tokens with next.

  • I know why to use one Scanner for System.in and not close it.

  • I can recognise InputMismatchException and NoSuchElementException and say what caused each.