Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Java  Module 1 – Start here: JDK 25 LTS and your first programs

Reading input with IO.readln and Scanner

Read lines with IO.readln, turn text into numbers safely, read until the input ends, and use Scanner without the nextInt-then-nextLine trap.

  • Beginner
  • 25 minutes
  • Examples run with Java 25.0.4.1 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 25 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Read lines with IO.readln, detect the end of input and loop over every line
  • Convert text with Integer.parseInt and Double.parseDouble, and check each result
  • Read tokens with a Scanner in a fixed locale, and avoid the nextInt-then-nextLine trap
  • Choose one reader for System.in, and a BufferedReader for very large inputs

Before you start

A program that adds up marks receives them as text: the line 72 is the two characters 7 and 2 until something converts it, and the line twelve is no number at all. Reading input well means getting that text in, turning it into values, and noticing at once when it is wrong or runs out.

On JDK 25 the simplest way to read standard input: The stream a program reads its input from, System.in in Java. It is the keyboard of the terminal unless the shell connects a file with < or the output of another command with |. is IO.readln(), which returns one line at a time and null when the input ends; Integer.parseInt and Double.parseDouble turn a line into a number. A Scanner reads numbers wherever the line breaks fall, and a BufferedReader reads large inputs fast. Each section runs one of them on real input and shows the mistake it invites: a word where a number should be, a line break left behind, two readers fighting over the same bytes, and a million numbers against a time limit.

Standard input reaches a program as text, through one reader

A program’s standard input is the keyboard of the terminal it runs in, unless the shell connects it to something else: a file with <, as in java SumLines.java < numbers.txt, or the output of another command with |. That is how an online judge or a test script feeds a program, and how every session on this page does it. When you type the input yourself, the program waits at each read until you press Enter.

Java calls this stream System.in, and a program reads it through one of three readers:

Standard input goes to one of three readers, IO.readln, Scanner or BufferedReader; parseInt or parseDouble turn text into numbers.Standard inputkeyboard, < file or | pipePick one readerInteger.parseIntDouble.parseDoubletext to a numberYour programIO.readln()one line as a Stringnull when the input endsScannernextInt(), nextDouble()and next() read tokensBufferedReaderreadLine(), then split itfast on large inputstextScanner converts

Three ways to read standard input, and where the numbers come from

Text description of the diagram

The diagram runs from top to bottom.

  1. Standard input comes from the keyboard, or from a file or a pipe that the shell connects with < or |.
  2. It goes to one reader, chosen for the whole program, from three stacked in a box labelled "Pick one reader": IO.readln(), which returns one line as a String and null when the input has ended; Scanner, whose nextInt(), nextDouble() and next() read tokens, the pieces between spaces and line breaks; and BufferedReader, whose readLine() returns a line for the program to split, and which is fast on large inputs.
  3. The text that a reader returns goes to Integer.parseInt or Double.parseDouble, which turn it into a number for your program.
  4. A dashed arrow labelled "Scanner converts" goes from the readers straight to the program, because nextInt() and nextDouble() already return numbers.

Whichever reader you choose, it hands you text: IO.readln() gives the line 42 as the String "42", two characters long. Integer.parseInt and Double.parseDouble turn such text into numbers; only a Scanner converts by itself, which is the dashed arrow in the figure. The box around the readers says pick one: a program uses a single reader for all its input, for a reason that the section on mixing readers shows with a run.

Checkpoint

Check: Standard input and its readers

  1. Question 1 of 2 Which command makes the file numbers.txt the standard input of SumLines.java?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: java SumLines.java < numbers.txt

    The shell connects standard input to a file with <, or to the output of another command with |, as in cat numbers.txt | java SumLines.java. A word after the file name is a command-line argument: the program receives it in args and does not read it as input.

  2. Question 2 of 2 IO.readln() has just returned the line 42 into line. Which expression gives the int 42?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Integer.parseInt(line.strip())

    A line is text even when it holds digits: "42" is a String of two characters. Integer.parseInt converts it, and strip() makes sure that a space around the digits does not stop the conversion.

IO.readln returns the next line, or null once the input has ended

IO.readln("Your age: ") prints its prompt, without a line break, and then reads one line. This program asks for a name and an age, and keeps asking until the age is a whole number from 1 to 120:

AgeCheck.java Java · AgeCheck.java
// Asks for a name and an age, and asks again until the age is a whole number from 1 to 120.
void main() {
    String name = IO.readln("Your name: ");
    while (true) {
        String text = IO.readln("Your age: ");
        if (text == null) {
            IO.println("The input ended before a valid age.");
            return;
        }
        try {
            int age = Integer.parseInt(text.strip());
            if (age >= 1 && age <= 120) {
                IO.println("Hello, " + name.strip() + ". Next year you will be " + (age + 1) + ".");
                return;
            }
            IO.println(age + " is not an age from 1 to 120.");
        } catch (NumberFormatException e) {
            IO.println("Not a whole number: " + e.getMessage());
        }
    }
}
Wrong answers first, then an input that runs out Python · age_session.py
from session import run

# Three wrong answers, then a good one; then an input that ends before any valid age.
run("""
cat age-input.txt
java AgeCheck.java < age-input.txt
java AgeCheck.java < age-short.txt
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ cat age-input.txt
Asha Rao
nineteen
250
 19
$ java AgeCheck.java < age-input.txt
Your name: Your age: Not a whole number: For input string: "nineteen"
Your age: 250 is not an age from 1 to 120.
Your age: Hello, Asha Rao. Next year you will be 20.
$ java AgeCheck.java < age-short.txt
Your name: Your age: Not a whole number: For input string: "abc"
Your age: The input ended before a valid age.

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 age_session.py

Step through both runs and watch what the program does with each line it receives, and what it prints in reply:

Interactive · message by message AgeCheck.java reading its input one line at a time Step through both runs of the session. Each step is one line that IO.readln returns, or one line the program prints.
AgeCheck.java reading its input one line at a time, step 11 of 11. Messages so far: AgeCheck.java to Terminal: Your name: ; Standard input to AgeCheck.java: "Asha Rao"; Standard input to AgeCheck.java: "nineteen"; AgeCheck.java to Terminal: Not a whole number: …; Standard input to AgeCheck.java: "250"; AgeCheck.java to Terminal: 250 is not an age …; Standard input to AgeCheck.java: " 19"; AgeCheck.java to Terminal: Hello, Asha Rao. …; Standard input to AgeCheck.java: "abc"; Standard input to AgeCheck.java: null; AgeCheck.java to Terminal: The input ended ….Standard inputage-short.txtAgeCheck.javaname = "Ravi"Terminalstandard outputYour name: "Asha Rao""nineteen"Not a whole number: …"250"250 is not an age …" 19"Hello, Asha Rao. …"abc"nullThe input ended …

The drawing shows the whole scene; its 11 steps are listed below.

Every step as text
  1. The first prompt. IO.readln("Your name: ") first prints its prompt, without a line break, so the answer you type would appear on the same line.
  2. The first line. Then it reads one line and returns it without its line break: the String "Asha Rao", which the program keeps as name.
  3. Text, not a number. After the prompt Your age:, the next line is nineteen. Integer.parseInt cannot turn it into an int and throws a NumberFormatException.
  4. Explain and ask again. The catch block prints the reason the exception gives, For input string: "nineteen", and the loop asks for the age again instead of stopping.
  5. A number out of range. The next line, 250, is a whole number, so parseInt converts it without complaint. The range check refuses it: converting and checking are two separate steps.
  6. Say why. The program prints 250 is not an age from 1 to 120. and asks once more.
  7. A space in front. The fourth line is 19 with a space in front. strip() removes the space before parseInt sees the text, and 19 passes the range check.
  8. Done. The program prints Hello, Asha Rao. Next year you will be 20. and returns, so it never asks for another line.
  9. A shorter input. The second run reads age-short.txt, which holds only Ravi and abc. The name is read, and abc fails to parse, as nineteen did.
  10. The input has ended. When the program asks for the age again, no line is left. IO.readln returns null, the sign that the input has ended.
  11. Stop, do not fail. The check text == null catches it: the program prints The input ended before a valid age. and returns. Without the check, text.strip() would fail with a NullPointerException.

What happened, line by line:

  • The prompts and the answers look run together because the input came from a file: the program printed each prompt, then read a line without showing it. In a terminal your own typing appears after each prompt.
  • nineteen is not a number, so Integer.parseInt threw a NumberFormatException. The try block caught it, and e.getMessage() gave the reason, For input string: "nineteen". Module 8 covers exceptions in depth; here it is enough that catch lets the program explain the problem and ask again instead of stopping.
  • 250 is a whole number, so the conversion worked; the range check refused it. Converting and checking are two separate steps, and a program needs both.
  • 19 arrived with a space in front. strip() removed the space before parseInt saw the text.
  • In the second run the input ended after abc. The next IO.readln returned null, and the program said so instead of waiting for an answer that would never come. Without that check, text.strip() would fail with a NullPointerException.

The prompt goes to standard output, the same place as the program’s results, so a program that writes its results to a file with > also writes its prompts there. Programs that read data rather than talk to a person usually call IO.readln() without a prompt.

Key idea

IO.readln hands over each line as text and null at the end; parseInt then converts or throws, and only after that can the program check whether the number makes sense.

Checkpoint

Check: Reading a line with IO.readln

  1. One question AgeCheck.java reads the line 250. Which part of the program refuses it?

    Choose one answer.

    Show the answer: One question

    Answer: The range check age >= 1 && age <= 120, after parseInt has converted the text

    Converting and checking are two separate steps. Integer.parseInt turns "250" into 250, and the program then checks the range itself and prints 250 is not an age from 1 to 120.

parseInt takes a sign and digits; parseDouble takes far more

Most input bugs happen at the conversion, so it pays to know exactly which texts the two methods take. This program gives the same thirteen texts to both of them, and prints refused wherever one threw a NumberFormatException:

Parse.java Java · Parse.java
// What Integer.parseInt and Double.parseDouble make of the same texts; "refused" means NumberFormatException.
void main() {
    String[] texts = {"42", "+42", "-7", " 42", "4_2", "42.0", "", "2147483648", "२०२६", "3,5", "1e3", "NaN", "Infinity"};
    IO.println(String.format("%-14s%-12s%s", "text", "parseInt", "parseDouble"));
    for (String text : texts) {
        IO.println(String.format("%-14s%-12s%s", "\"" + text + "\"", asInt(text), asDouble(text)));
    }
}

String asInt(String text) {
    try {
        return String.valueOf(Integer.parseInt(text));
    } catch (NumberFormatException e) {
        return "refused";
    }
}

String asDouble(String text) {
    try {
        return String.valueOf(Double.parseDouble(text));
    } catch (NumberFormatException e) {
        return "refused";
    }
}
Thirteen texts, both conversions Python · parse_session.py
from session import run

# Thirteen texts, each given to Integer.parseInt and to Double.parseDouble.
run("""
java Parse.java
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java Parse.java
text          parseInt    parseDouble
"42"          42          42.0
"+42"         42          42.0
"-7"          -7          -7.0
" 42"         refused     42.0
"4_2"         refused     refused
"42.0"        refused     42.0
""            refused     refused
"2147483648"  refused     2.147483648E9
"२०२६"        2026        refused
"3,5"         refused     refused
"1e3"         refused     1000.0
"NaN"         refused     NaN
"Infinity"    refused     Infinity

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 parse_session.py

Read the table one column at a time:

  • Integer.parseInt accepts an optional + or - followed by digits, nothing else. A space at either end, the underscore that Java source code allows in 4_2, a decimal point and the empty string are all refused.
  • 2147483648 is refused too: it is one more than Integer.MAX_VALUE, and parseInt reports a number that does not fit an int instead of wrapping it around. parseDouble reads it as 2.147483648E9.
  • २०२६, written in Devanagari digits, became 2026. According to its documentation, parseInt accepts every character that Character.digit counts as a digit, and that covers the decimal digits of many scripts, not only 0 to 9. Double.parseDouble refused it: it takes only 0 to 9, and its documentation points to NumberFormat for other digits.
  • Double.parseDouble removes spaces at both ends by itself, reads 1e3 as 1000.0, and refuses the comma of 3,5.
  • It also accepts NaN (“not a number”) and Infinity. A program that reads measurements should therefore check the result with Double.isFinite(value) as well as its range.

Two habits follow. Call strip() on a line before converting it, and treat every conversion as something that can fail: catch NumberFormatException where the text comes in, and say which input was wrong.

Converting a line exactly as it was typed

Integer.parseInt(line) refuses 19, a 19 typed after a space, and the program rejects a perfectly good answer. Integer.parseInt(line.strip()) gives 19, because strip() removes the spaces at both ends first.

Unicode Character Inspector When a line that looks like 42 refuses to parse, paste it here to see hidden characters such as a non-breaking space or a byte order mark.

Checkpoint

Check: What parseInt and parseDouble accept

  1. Question 1 of 2 Which of these texts does Integer.parseInt accept? Choose every one.

    Choose every answer that is right.

    Show the answer: Question 1 of 2

    Answer:

    • "-7"
    • "+42"

    Integer.parseInt accepts an optional + or - followed by digits, and nothing else. In the table, +42 and -7 were converted, while " 42", 4_2 and 42.0 were refused.

  2. Question 2 of 2 A file of temperatures may hold the line Infinity. Which check stops it from being used as a reading?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Double.isFinite(value), after Double.parseDouble

    Double.parseDouble accepts NaN and Infinity as well as numbers, so a program that reads measurements checks Double.isFinite(value) as well as the range.

A loop reads every line until IO.readln returns null

Many inputs do not say how many lines follow, so a program reads until the end of input: The point where standard input has no characters left: a file has been read to its end, or the user pressed Ctrl-D (macOS, Linux) or Ctrl-Z and Enter (Windows). IO.readln then returns null., when IO.readln() returns null. This one adds up whole numbers, one per line:

SumLines.java Java · SumLines.java
// Adds up the whole numbers on standard input, one per line, until the input ends.
void main() {
    long total = 0;
    int count = 0;
    int lineNumber = 0;
    String line;
    while ((line = IO.readln()) != null) {
        lineNumber++;
        String text = line.strip();
        if (text.isEmpty()) {
            continue;
        }
        try {
            total += Integer.parseInt(text);
            count++;
        } catch (NumberFormatException e) {
            System.err.println("line " + lineNumber + ": \"" + line + "\" is not a whole number, skipped");
        }
    }
    IO.println(count + " numbers, total " + total);
}
A file, a pipe and an empty input Python · sum_session.py
from session import run

# The same program with a file, a pipe and an empty input.
run("""
cat numbers.txt
java SumLines.java < numbers.txt
printf '2\\n3' | java SumLines.java
java SumLines.java < /dev/null
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ cat numbers.txt
12
30

 8
twelve
50
$ java SumLines.java < numbers.txt
line 5: "twelve" is not a whole number, skipped
4 numbers, total 100
$ printf '2\n3' | java SumLines.java
2 numbers, total 5
$ java SumLines.java < /dev/null
0 numbers, total 0

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 sum_session.py

The loop condition (line = IO.readln()) != null does two jobs: it stores the next line in line, and it stops the loop when there is none. Step through the first run, one call of IO.readln at a time, and watch the total:

Interactive · message by message SumLines.java reading numbers.txt until the input ends Step through the loop. Each step is one call of IO.readln in the loop's condition and what the body did with the line.
SumLines.java reading numbers.txt until the input ends, step 9 of 9. Messages so far: Standard input to SumLines.java: "12"; Standard input to SumLines.java: "30"; Standard input to SumLines.java: ""; Standard input to SumLines.java: " 8"; Standard input to SumLines.java: "twelve"; SumLines.java to Terminal: line 5: … skipped; Standard input to SumLines.java: "50"; Standard input to SumLines.java: null; SumLines.java to Terminal: 4 numbers, total 100.Standard inputnumbers.txtSumLines.javatotal 100, count 4Terminalstdout and stderr"12""30"""" 8""twelve"line 5: … skipped"50"null4 numbers, total 100

The drawing shows the whole scene; its 9 steps are listed below.

Every step as text
  1. Line 1. The condition (line = IO.readln()) != null stores "12" in line and lets the body run. strip() changes nothing, and parseInt adds 12 to the total.
  2. Line 2. The next call returns "30", and the total becomes 42.
  3. A blank line. Line 3 is empty. strip() leaves "", isEmpty() is true, and continue goes straight back to the condition: nothing is added.
  4. A space in front. Line 4 is 8 with a space in front. strip() removes the space, and the total becomes 50.
  5. Not a number. Line 5 is twelve. parseInt throws a NumberFormatException, and the catch block reports the line instead of adding it.
  6. To standard error. The report goes to standard error with System.err.println, so it stays on the screen even when the results are saved to a file with >.
  7. Line 6. The last line, 50, makes the total 100 and the count 4.
  8. The input has ended. No line is left, so IO.readln returns null. The condition is false, and the loop ends without running its body again.
  9. The result. After the loop the program prints its one line of results, 4 numbers, total 100, on standard output.

Inside the loop, a blank line is skipped with continue, and a line that is not a number is reported on The second output stream of a program, System.err in Java, meant for error messages. It reaches the terminal even when standard output is redirected to a file with >. with its line number (System.err.println), so the message stays visible even when the results are saved with >. Line 5, twelve, was skipped, and the other four numbers added up to 100.

The second run shows that the last line counts even without a line break after it: printf '2\n3' sends no final line break, and both numbers arrived. The third run reads from /dev/null, an input that is empty from the start, and the very first call returned null.

When you type the input yourself, you tell the program it has ended with a key: Ctrl-D in a macOS or Linux terminal, Ctrl-Z followed by Enter in a Windows console. Feeding a file with < works in macOS and Linux shells and in the Windows Command Prompt. PowerShell keeps < reserved for future use, so there Get-Content numbers.txt | java SumLines.java does the same job.

Checkpoint

Check: Reading until the input ends

  1. Question 1 of 2 SumLines.java reads four lines: 7, an empty line, x and 3. What count does it print?

    Type a number.

    A hint

    Follow each line through the loop of the figure. Which ones reach the line that adds to the total?

    Show the answer: Question 1 of 2

    Answer: 2 numbers

    The empty line is skipped with continue, and x is reported on standard error and skipped. Only 7 and 3 are added, so the program prints 2 numbers, total 10.

  2. Question 2 of 2 You type numbers into SumLines.java in a macOS or Linux terminal. How do you tell it that the input has ended?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Press Ctrl-D

    In a macOS or Linux terminal Ctrl-D ends typed input, and in a Windows console Ctrl-Z followed by Enter does. IO.readln then returns null, and the loop stops.

A Scanner reads tokens, wherever the line breaks fall

A Scanner splits its input into token: A piece of input between two stretches of whitespace (spaces, tabs or line breaks), such as 72 or eighty. A Scanner reads one token with next(), or converts it with nextInt() or nextDouble(). wherever there is whitespace (spaces, tabs or line breaks) and converts each token when you ask for it. nextInt() returns the next token as an int, nextDouble() as a double and next() as a String. Because line breaks are just whitespace to it, a count followed by that many numbers can be laid out in any way:

Tokens.java Java · Tokens.java
// Reads a count, then that many marks, wherever the line breaks fall.
void main() {
    Scanner in = new Scanner(System.in, System.getProperty("stdin.encoding"));
    int n = in.nextInt();
    int sum = 0;
    for (int i = 0; i < n; i++) {
        sum += in.nextInt();
    }
    IO.println(n + " marks, sum " + sum);
}
Two layouts, a word among the numbers, and too few numbers Python · tokens_session.py
from session import run

# The same five marks on two lines and on one line; then a word among the numbers, and too few numbers.
run("""
printf '5\\n72 85\\n64 91 57\\n' | java Tokens.java
printf '5 72 85 64 91 57\\n' | java Tokens.java
printf '3\\n72 eighty 64\\n' | java Tokens.java
printf '3\\n72 64\\n' | java Tokens.java
""", expect_failure=[
    "printf '3\\n72 eighty 64\\n' | java Tokens.java",
    "printf '3\\n72 64\\n' | java Tokens.java",
])

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ printf '5\n72 85\n64 91 57\n' | java Tokens.java
5 marks, sum 369
$ printf '5 72 85 64 91 57\n' | java Tokens.java
5 marks, sum 369
$ printf '3\n72 eighty 64\n' | java Tokens.java
Exception in thread "main" java.util.InputMismatchException
	at java.base/java.util.Scanner.throwFor(Scanner.java:977)
	at java.base/java.util.Scanner.next(Scanner.java:1632)
	at java.base/java.util.Scanner.nextInt(Scanner.java:2297)
	at java.base/java.util.Scanner.nextInt(Scanner.java:2251)
	at Tokens.main(Tokens.java:7)
[exit status 1]
$ printf '3\n72 64\n' | java Tokens.java
Exception in thread "main" java.util.NoSuchElementException
	at java.base/java.util.Scanner.throwFor(Scanner.java:975)
	at java.base/java.util.Scanner.next(Scanner.java:1632)
	at java.base/java.util.Scanner.nextInt(Scanner.java:2297)
	at java.base/java.util.Scanner.nextInt(Scanner.java:2251)
	at Tokens.main(Tokens.java:7)
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 tokens_session.py

The first two runs printed the same 5 marks, sum 369 for five marks on two lines and on one line. Step through the first of them, one call of nextInt() at a time, and then the two inputs on which the program stopped:

Interactive · message by message A Scanner handing Tokens.java its marks, token by token Step through the calls of nextInt(). The line breaks of the input are whitespace to the Scanner, like the spaces.
A Scanner handing Tokens.java its marks, token by token, step 8 of 8. Messages so far: Standard input to Scanner: 5 ⏎ 72 85 ⏎ 64 91 57 ⏎; Scanner to Tokens.java: 5; Scanner to Tokens.java: 72; Scanner to Tokens.java: 85; Scanner to Tokens.java: 64; Scanner to Tokens.java: 91, then 57.Standard input3 ⏎ 72 64Scannerno token leftTokens.java5 marks, sum 3695 ⏎ 72 85 ⏎ 64 91 57 ⏎572856491, then 57

The drawing shows the whole scene; its 8 steps are listed below.

Every step as text
  1. The input arrives. The Scanner reads standard input and splits it into tokens wherever there is whitespace: spaces, tabs and line breaks alike.
  2. The count. The first nextInt() returns the token 5, converted to an int, so the loop will read five marks.
  3. Across a line break. The next call skips the line break after 5, which is only whitespace to the Scanner, and returns 72.
  4. The same line. The third call returns 85, the second token of line 2.
  5. The next line. The line break after 85 is skipped the same way, and the call returns 64 from line 3.
  6. The last two. Two more calls return 91 and 57. The loop has read its five marks, and the program prints 5 marks, sum 369.
  7. A word among the numbers. On the input 3, then 72 eighty 64, the second mark is the token eighty. nextInt() throws an InputMismatchException and leaves eighty unread.
  8. Too few numbers. On the input 3, then 72 64, the third nextInt() finds no token at all and throws a NoSuchElementException.

On eighty the Scanner threw an InputMismatchException, with no message at all; the documentation adds that the Scanner leaves such a token unread, so a loop that simply tries nextInt() again meets it again. When the input ended after two of three numbers, it threw a NoSuchElementException. To test before reading, use hasNextInt(), which says whether the next token is a whole number without reading it, and next() to skip a token that is not.

The Scanner is created with new Scanner(System.in, System.getProperty("stdin.encoding")). The second argument names the The rule that turns characters into bytes and back again, such as UTF-8. Bytes decoded with the wrong one come out as the wrong characters. of standard input. Without it, a Scanner decodes the bytes with the default charset, which is UTF-8 since JDK 18 (JEP 400). The documentation of System.in asks programs to decode it with the encoding that the stdin.encoding property names instead. Standard input is the keyboard or another source that the host environment or the user sets up, and stdin.encoding is the name of its encoding. IO.readln uses stdin.encoding by itself.

Checkpoint

Check: Tokens and the Scanner

  1. One question A Scanner's input is 72 eighty 64, and the program has read 72 with nextInt(). What does hasNextInt() return now, and which token comes next?

    Choose one answer.

    Show the answer: One question

    Answer: false, and the next token is still eighty

    hasNextInt() says whether the next token is a whole number without reading it. On eighty it is false, and eighty stays the next token until next() reads it.

A Scanner reads numbers the way its locale writes them

A Scanner also reads numbers the way its A setting that names a language and a region, such as de-DE for German in Germany or en-IN for English in India, and decides how numbers, dates and text are written there. writes them. Its initial locale is the computer’s format locale, so the same program can read the same file differently on two computers:

LocaleNumbers.java Java · LocaleNumbers.java
// How a Scanner reads the same four texts under three locales.
void main() {
    Locale[] locales = {Locale.ROOT, Locale.of("en", "IN"), Locale.GERMANY};
    for (String text : new String[] {"3.5", "3,5", "100,000", "1,00,000"}) {
        List<String> results = new ArrayList<>();
        for (Locale locale : locales) {
            Scanner in = new Scanner(text).useLocale(locale);
            String value = in.hasNextInt() ? "int " + in.nextInt()
                    : in.hasNextDouble() ? "double " + in.nextDouble()
                    : "no number";
            results.add(locale.toLanguageTag() + ": " + value);
        }
        IO.println(String.format("%-9s", text) + String.join(" | ", results));
    }
}
One text, three locales Python · locale_session.py
from session import run

# und is Locale.ROOT, the locale of no country and no language.
run("""
java LocaleNumbers.java
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java LocaleNumbers.java
3.5      und: double 3.5 | en-IN: double 3.5 | de-DE: no number
3,5      und: no number | en-IN: no number | de-DE: double 3.5
100,000  und: int 100000 | en-IN: int 100000 | de-DE: double 100.0
1,00,000 und: no number | en-IN: no number | de-DE: no number

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 locale_session.py

Each row is one text and each column one locale. In the German locale (de-DE), where the decimal separator is a comma, 3.5 was no number at all and 3,5 became 3.5. Locale.ROOT (shown as und) and en-IN accepted a comma between groups of three digits, so 100,000 became the whole number 100000; in German it became the decimal 100.0. For data written with a decimal point, call useLocale(Locale.ROOT) on the Scanner, so that it reads the same text the same way on every computer.

Indian number formats

None of the three locales read 1,00,000, the way one lakh is written in India, because a Scanner accepts group separators only between groups of three digits. Integer.parseInt refuses every comma. If a file or a form holds Indian-style grouping, remove the commas before converting, for example with text.replace(",", ""), and then check the result’s range as usual.

Checkpoint

Check: A Scanner's locale

  1. Question 1 of 2 A program reads data written with a decimal point, such as 3.5. Which call makes its Scanner read the data the same way on every computer?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: in.useLocale(Locale.ROOT)

    A Scanner starts with the computer's format locale, so the same file can read differently on two computers. useLocale(Locale.ROOT) fixes the format for data written with a decimal point.

  2. Question 2 of 2 An invoice from India writes an amount as 1,00,000. What does a Scanner make of it under Locale.ROOT, en-IN and de-DE?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: No number, under all three

    None of the three locales read 1,00,000, because a Scanner accepts group separators only between groups of three digits. Remove the commas first, with text.replace(",", ""), then convert the text and check its range.

nextLine() after nextInt() returns the rest of the line, often empty

Reading a number with nextInt() and then a whole line with nextLine() is the most common Scanner bug of all:

Trap.java Java · Trap.java
// An age with nextInt(), then a full name with nextLine(): the classic trap.
void main() {
    Scanner in = new Scanner(System.in, System.getProperty("stdin.encoding"));
    IO.print("Age: ");
    int age = in.nextInt();
    IO.print("Full name: ");
    String name = in.nextLine();
    IO.println("Hello, [" + name + "], age " + age);
}
Two fixes

Fix 1: TrapFixed.java · TrapFixed.java

// Fix 1: after nextInt(), one nextLine() call throws away the rest of that line.
void main() {
    Scanner in = new Scanner(System.in, System.getProperty("stdin.encoding"));
    IO.print("Age: ");
    int age = in.nextInt();
    in.nextLine();
    IO.print("Full name: ");
    String name = in.nextLine();
    IO.println("Hello, [" + name + "], age " + age);
}

Fix 2: LinesOnly.java · LinesOnly.java

// Fix 2: read whole lines only, and turn the one that holds a number into a number.
void main() {
    int age = Integer.parseInt(IO.readln("Age: ").strip());
    String name = IO.readln("Full name: ");
    IO.println("Hello, [" + name + "], age " + age);
}
The trap and both fixes, on the same input Python · trap_session.py
from session import run

# One input file for all three programs: an age on the first line, a full name on the second.
run("""
cat age-name.txt
java Trap.java < age-name.txt
java TrapFixed.java < age-name.txt
java LinesOnly.java < age-name.txt
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ cat age-name.txt
19
Asha Rao
$ java Trap.java < age-name.txt
Age: Full name: Hello, [], age 19
$ java TrapFixed.java < age-name.txt
Age: Full name: Hello, [Asha Rao], age 19
$ java LinesOnly.java < age-name.txt
Age: Full name: Hello, [Asha Rao], age 19

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 trap_session.py

The input is 19 on one line and Asha Rao on the next, yet Trap.java printed an empty name, []. Step through the input as the Scanner sees it, two lines and their line breaks, and watch where each call stops:

Interactive · step by step Where nextInt() and nextLine() stop in age-name.txt Step through the calls of Trap.java, then the one call more that TrapFixed.java makes. A box marked done has been read.
Where nextInt() and nextLine() stop in age-name.txt, step 6 of 6. Showing 19 (read by nextInt()), line break (nextLine() returned ""), Asha Rao (read by one more nextLine()), line break. In focus: 19, Asha Rao.19read by nextInt()line breaknextLine() returned ""Asha Raoread by one more nextLine()line breakends line 2

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The input. The file holds two lines, 19 and Asha Rao, each ended by a line break. The Scanner starts in front of the 1 of 19.
  2. nextInt(). nextInt() reads the token 19, returns the int 19 and stops right after it, in front of the first line break.
  3. nextLine(). nextLine() returns the rest of the current line and steps over its line break. The rest of line 1 is empty, so it returns "" at once.
  4. The trap. Trap.java prints Hello, [], age 19 and ends. Asha Rao was never read; the square brackets make the empty name visible.
  5. Fix 1. TrapFixed.java makes the same two calls and throws the empty string away, then calls nextLine() once more. That call returns Asha Rao, the whole of line 2.
  6. Fix 2. LinesOnly.java never stops in the middle of a line: IO.readln returns "19", which parseInt converts, and the next IO.readln returns Asha Rao.

nextInt() read the token 19 and stopped right after it, in front of the line break. nextLine() returns the rest of the current line, and the rest of that line was empty, so it returned an empty string at once. The square brackets are there to make the empty string visible.

Fix 1 calls nextLine() once more right after nextInt(), which throws away the rest of the line that held the number. Fix 2 never mixes the two styles: it reads every line as a line and converts the one that holds a number. Fix 2 is usually the better habit, because each line arrives whole, and a bad one can be reported as it was typed.

Key idea

After nextInt() the line break is still waiting, so the next nextLine() returns what is left of that line: throw it away with one more nextLine(), or read whole lines only.

Checkpoint

Check: The nextInt-then-nextLine trap

  1. One question The input is 7 on one line and Ravi Kumar on the next. A program calls in.nextInt() and then in.nextLine(). What does nextLine() return?

    Choose one answer.

    Show the answer: One question

    Answer: An empty string

    nextInt() reads only the token and stops in front of the line break. nextLine() returns the rest of the current line, which is empty, just as Trap.java printed Hello, [], age 19.

Two readers on one System.in lose data without an error

Each of the three readers reads ahead: it fetches a large block of bytes and keeps what it has not returned yet in a A block of memory where a reader keeps the bytes or characters it has fetched but not yet returned, so that it can read its source in large pieces. of its own. That is why a program must not start with one reader and continue with another. The documentation of IO is blunt about it: once a program has called a readln method, nothing is promised about what any other reader of System.in gets. Here is what that looks like:

Mixed.java Java · Mixed.java
// Reads a title with IO.readln, then hands System.in to a Scanner for the numbers that follow: a mistake.
void main() {
    String title = IO.readln();
    Scanner rest = new Scanner(System.in, System.getProperty("stdin.encoding"));
    int count = 0;
    long first = -1;
    while (rest.hasNextLong()) {
        long n = rest.nextLong();
        if (count == 0) {
            first = n;
        }
        count++;
    }
    IO.println("title: " + title);
    IO.println("numbers the Scanner found: " + count + ", the first: " + first);
}
IO.readln for the title, a Scanner for the rest Python · mixed_session.py
from session import run

# A small input, then a title followed by the 20,000 numbers 0 to 19999, one per line.
run("""
java Mixed.java < class-7b.txt
(echo Marks; seq 0 19999) > marks-big.txt
java Mixed.java < marks-big.txt
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java Mixed.java < class-7b.txt
title: Marks of class 7B
numbers the Scanner found: 0, the first: -1
$ (echo Marks; seq 0 19999) > marks-big.txt
$ java Mixed.java < marks-big.txt
title: Marks
numbers the Scanner found: 18141, the first: 859

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 mixed_session.py

With the small file, the Scanner found no numbers at all: IO.readln had read the whole file into its buffer while fetching the first line. With a title followed by the 20,000 numbers from 0 to 19999, the Scanner found only 18,141 of them, and the first number it read was 859: not the 0 that follows the title, but the last three digits of the line 1859. In this run IO.readln had already taken the first 8,192 bytes, which ended in the middle of 1859. Nothing failed or warned; the program simply computed with the wrong data. Step through where each reader’s bytes came from:

Interactive · message by message IO.readln and a Scanner sharing one System.in Step through Mixed.java on marks-big.txt, then on the small class-7b.txt. Watch where each reader's bytes come from.
IO.readln and a Scanner sharing one System.in, step 6 of 6. Messages so far: System.in to IO.readln: 8,192 bytes; System.in to Scanner: 859 ⏎ 1860 ⏎ 1861 ….System.inclass-7b.txtIO.readlnreturned the titleScannerno numbers found8,192 bytes859 ⏎ 1860 ⏎ 1861 …

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. One block. To return the first line, IO.readln reads a block of bytes from System.in, not one line: 8,192 bytes, which hold the title, the numbers 0 to 1858 and the 1 of 1859.
  2. The title. It returns the line Marks and keeps the other 8,186 bytes in a buffer of its own, for readln calls that never come.
  3. A second reader. new Scanner(System.in) reads the same stream, which now continues where the block ended, in the middle of 1859.
  4. A wrong value. The first token the Scanner finds is 859, the last three digits of 1859: a number that is not in the file at all.
  5. Lost values. It counts 18,141 numbers, 859 and then 1860 to 19999. The numbers 0 to 1858 stay in the buffer of IO.readln, and nothing fails or warns.
  6. A small file. class-7b.txt has only 33 bytes, so the first block takes the whole file. The Scanner finds no number at all, and the program prints 0 and -1.

The cure is to choose one reader when the program starts and use it for all input. A Scanner can read lines too, with nextLine(), and a BufferedReader reads lines with readLine().

Key idea

Every reader buffers more than it returns, so one reader owns System.in for the whole run: a second reader starts wherever the first one’s block happened to end.

Checkpoint

Check: One reader for System.in

  1. Question 1 of 2 marks-big.txt holds a title and the 20,000 numbers 0 to 19999, and the Scanner of Mixed.java counted 18,141 numbers. How many of the 20,000 did it never see?

    Type a number.

    A hint

    The Scanner's first number was 859, the end of 1859. Which numbers come before 1859 in the file?

    Show the answer: Question 1 of 2

    Answer: 1859 numbers

    The numbers 0 to 1858, 1,859 of them, stayed in the buffer of IO.readln. The Scanner then saw 859, a wrong value cut from 1859, and the 18,140 numbers from 1860 to 19999: 18,141 in all.

  2. Question 2 of 2 A program must read a title line and then numbers from standard input. Which plan reads all of them?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Choose one reader when the program starts, and use it for the title and for every number

    Each reader reads ahead into a buffer of its own, so the cure is one reader for all input: IO.readln for every line, or one Scanner, which reads lines with nextLine() as well as tokens.

A BufferedReader reads a million numbers several times faster

A Scanner matches every token against A pattern that describes text, such as one or more digits with an optional sign in front. A Scanner checks every token it reads against such patterns., which costs time on large inputs. A BufferedReader returns whole lines instead, and the program cuts each line into numbers itself: with a StringTokenizer, the classic choice in contest code, or with String.split, which the documentation of StringTokenizer recommends for new code because StringTokenizer is a legacy class. This program reads the same million numbers in all three ways and times only the reading:

ReadSpeed.java Java · ReadSpeed.java
// Reads every whole number on standard input in one of three ways, and times only the reading.
void main(String[] args) throws IOException {
    String how = args[0];
    String charset = System.getProperty("stdin.encoding");
    long start = System.nanoTime();
    long sum = 0;
    int count = 0;
    if (how.equals("scanner")) {
        Scanner in = new Scanner(System.in, charset);
        while (in.hasNextInt()) {
            sum += in.nextInt();
            count++;
        }
    } else {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in, charset));
        String line;
        while ((line = in.readLine()) != null) {
            if (how.equals("tokenizer")) {
                StringTokenizer tokens = new StringTokenizer(line);
                while (tokens.hasMoreTokens()) {
                    sum += Integer.parseInt(tokens.nextToken());
                    count++;
                }
            } else {
                for (String token : line.split(" ")) {
                    if (!token.isEmpty()) {
                        sum += Integer.parseInt(token);
                        count++;
                    }
                }
            }
        }
    }
    long ms = (System.nanoTime() - start) / 1_000_000;
    IO.println(how + ": " + count + " numbers, sum " + sum + ", " + ms + " ms");
}
MakeInput.java: a million numbers from a fixed seed Java · MakeInput.java
// Writes count whole numbers (1,000 per line) from a fixed seed, so every run makes the same file.
void main(String[] args) {
    int count = Integer.parseInt(args[0]);
    Random random = new Random(25);
    StringBuilder line = new StringBuilder();
    for (int i = 1; i <= count; i++) {
        line.append(random.nextInt(-1_000_000, 1_000_001));
        if (i % 1000 == 0 || i == count) {
            IO.println(line);
            line.setLength(0);
        } else {
            line.append(' ');
        }
    }
}
One million numbers, read twice in each of three ways Python · speed_session.py
from session import run

# One million numbers in a 7 MB file, read twice in each of three ways.
run("""
java MakeInput.java 1000000 > million.txt
java ReadSpeed.java scanner < million.txt
java ReadSpeed.java scanner < million.txt
java ReadSpeed.java tokenizer < million.txt
java ReadSpeed.java tokenizer < million.txt
java ReadSpeed.java split < million.txt
java ReadSpeed.java split < million.txt
""")

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java MakeInput.java 1000000 > million.txt
$ java ReadSpeed.java scanner < million.txt
scanner: 1000000 numbers, sum 1250132008, 463 ms
$ java ReadSpeed.java scanner < million.txt
scanner: 1000000 numbers, sum 1250132008, 430 ms
$ java ReadSpeed.java tokenizer < million.txt
tokenizer: 1000000 numbers, sum 1250132008, 70 ms
$ java ReadSpeed.java tokenizer < million.txt
tokenizer: 1000000 numbers, sum 1250132008, 130 ms
$ java ReadSpeed.java split < million.txt
split: 1000000 numbers, sum 1250132008, 95 ms
$ java ReadSpeed.java split < million.txt
split: 1000000 numbers, sum 1250132008, 91 ms

This output changes from run to run: The times depend on the computer and on what else it was doing; the count and the sum are the same in every run.

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 speed_session.py

All three found the same million numbers with the same sum. On an Apple M5 Pro, the Scanner took 400 to 900 ms over repeated runs, while the two BufferedReader versions took 60 to 300 ms, with no clear winner between StringTokenizer and split: the Scanner was several times slower in every run. Side by side:

Reader How it gets the numbers A million numbers, repeated runs
Scanner nextInt() finds and converts each token 400 to 900 ms
BufferedReader and StringTokenizer readLine(), then the line cut into tokens 60 to 300 ms
BufferedReader and split readLine(), then line.split(" ") 60 to 300 ms

For a few lines typed at a keyboard the difference does not matter. For a judge’s input of hundreds of thousands of numbers under a time limit of one or two seconds it can decide the verdict, and that is when a BufferedReader is worth its few extra lines. The lesson on fast input and output, in the module on DSA and placements, builds faster readers still.

Choosing a reader

Use IO.readln() for lines a person types, a Scanner for numbers spread over lines in any way, and a BufferedReader with split when the input runs to hundreds of thousands of numbers.

Checkpoint

Check: Reading large inputs fast

  1. One question A judge gives 300,000 numbers on a few long lines and a time limit of one second. Which input code does this lesson suggest?

    Choose one answer.

    Show the answer: One question

    Answer: A BufferedReader, with each line cut by split or a StringTokenizer

    For a few lines typed at a keyboard any reader will do. For an input of hundreds of thousands of numbers under a time limit of one or two seconds, a BufferedReader that cuts each line into numbers is worth its few extra lines.

Practise: a marks summary

Complete Marks.java so that it reads a count n and then n marks from 0 to 100, which may be spread over several lines with blank lines between them, and prints the lowest mark, the highest mark and the average with two decimals. For the input 5, then 72 85 64 91 57, it prints exactly:

  • Lowest: 57
  • Highest: 91
  • Average: 73.80

For n = 0 it prints No marks. A mark below 0 or above 100 is an error: print a message to standard error and stop with System.exit(1).

Marks.java: the exercise Java · Marks.java
// Exercise: read a count n, then n marks from 0 to 100, and print the lowest, the highest and the average.
// Replace the line below with your solution.
void main() {
    IO.println("TODO");
}

The session runs three sample tests, each comparing what the program printed with the expected output through diff, as in the earlier exercises. As given, the program prints TODO, so all three fail:

The sample tests before you start Python · marks_session.py
from session import run

# The sample tests: run Marks.java on three inputs and compare each output with the expected one.
TESTS = """
java Marks.java < marks-five.txt > got.txt; diff expected-five.txt got.txt && echo PASS
java Marks.java < marks-blank-lines.txt > got.txt; diff expected-blank-lines.txt got.txt && echo PASS
java Marks.java < marks-none.txt > got.txt; diff expected-none.txt got.txt && echo PASS
"""
run(TESTS, expect_failure=[line.strip() for line in TESTS.strip().splitlines()])

Output

# JDK in use: openjdk version "25.0.4.1" LTS
$ java Marks.java < marks-five.txt > got.txt; diff expected-five.txt got.txt && echo PASS
1,3c1
< Lowest: 57
< Highest: 91
< Average: 73.80
---
> TODO
[exit status 1]
$ java Marks.java < marks-blank-lines.txt > got.txt; diff expected-blank-lines.txt got.txt && echo PASS
1,3c1
< Lowest: 0
< Highest: 100
< Average: 50.00
---
> TODO
[exit status 1]
$ java Marks.java < marks-none.txt > got.txt; diff expected-none.txt got.txt && echo PASS
1c1
< No marks
---
> TODO
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 marks_session.py

First hint: a Scanner does not care about blank lines or how the marks are spread, so nextInt() in a for loop reads them all. Divide as double, not as int, and format the average with String.format(Locale.ROOT, "Average: %.2f", average), so that the decimal separator is a point on every computer.

Text Diff Paste the expected output and your program's output to see exactly which character differs, the way a judge compares them.

Then check all nine ideas in one short session. It picks the idea you have answered least well so far, asks one question at a time, and shows why each answer is right or wrong:

Practice that adapts to you

Practise this lesson

19 questions about 9 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 19 Which command feeds the output of cat numbers.txt to SumLines.java as its standard input?

    Choose one answer.

    Show the answer: Question 1 of 19

    Answer: cat numbers.txt | java SumLines.java

    | connects the output of one command to the standard input of the next, so cat numbers.txt | java SumLines.java reads the same lines as java SumLines.java < numbers.txt.

  2. Question 2 of 19 A program reads the lines 7 and 8 with IO.readln() into a and b, and prints a + b. It prints 78. Why?

    Choose one answer.

    Show the answer: Question 2 of 19

    Answer: Both lines are Strings, and + joins two Strings into one

    IO.readln returns text, and + between two Strings joins them, as "Hello, " + name does in AgeCheck.java. Convert each line with Integer.parseInt before adding.

  3. Question 3 of 19 The input holds the line Asha Rao followed by a line break. What does IO.readln() return?

    Choose one answer.

    Show the answer: Question 3 of 19

    Answer: "Asha Rao", without the line break

    Each call of IO.readln returns the next line as a String, without its line break, so the first call in AgeCheck.java returned "Asha Rao".

  4. Question 4 of 19 A program reads its data with IO.readln("Next: "), and you run it as java Prog.java < data.txt > out.txt. What lands in out.txt besides the results?

    Choose one answer.

    Show the answer: Question 4 of 19

    Answer: Every prompt, Next: once for each call

    IO.readln prints its prompt to standard output, so a program whose results are saved with > saves its prompts too. Programs that read data rather than talk to a person usually call IO.readln() without a prompt.

  5. Question 5 of 19 What does Integer.parseInt(" 42") do, with the space in front?

    Choose one answer.

    Show the answer: Question 5 of 19

    Answer: It throws a NumberFormatException

    parseInt accepts an optional sign followed by digits and nothing else, so the space makes the text invalid, as the table showed. Call strip() on the text first. Double.parseDouble, by contrast, removes spaces at both ends by itself.

  6. Question 6 of 19 A user typed 19 , with a space on each side. Which line gives the int 19?

    Choose one answer.

    Show the answer: Question 6 of 19

    Answer: Integer.parseInt(text.strip())

    Call strip() on a line before converting it: it removes spaces at both ends, which parseInt would refuse. In AgeCheck.java, " 19" became 19 this way.

  7. Question 7 of 19 What does IO.readln() return when the input has ended and no characters are left?

    Choose one answer.

    Show the answer: Question 7 of 19

    Answer: null

    The documentation of IO.readln says it returns null if the end of the stream has been reached without reading any characters. That is why while ((line = IO.readln()) != null) reads every line and then stops. An empty string means a blank line, which is a different thing.

  8. Question 8 of 19 A loop reads while (!(line = IO.readln()).isEmpty()), meant to stop at the end of the input. What happens when the input ends without a blank line?

    Choose one answer.

    Show the answer: Question 8 of 19

    Answer: A NullPointerException: IO.readln returns null, and the loop calls isEmpty() on it

    This loop stops only at a blank line. When the input ends first, IO.readln returns null and null.isEmpty() throws a NullPointerException. Compare with null, as SumLines.java does, and skip blank lines inside the loop.

  9. Question 9 of 19 Where does a Scanner split its input into tokens, unless it is told otherwise?

    Choose one answer.

    Show the answer: Question 9 of 19

    Answer: At whitespace: spaces, tabs and line breaks

    A Scanner's tokens are the pieces of text between whitespace, and spaces, tabs and line breaks all count as whitespace. nextInt(), nextDouble() and next() each read one token.

  10. Question 10 of 19 A Scanner reads nextInt() three times. Which input gives it 1, 2 and 3?

    Choose one answer.

    Show the answer: Question 10 of 19

    Answer: Any of them: 1 2 3 on one line, three lines, or 1 2 and then 3

    A Scanner splits its input at whitespace, and line breaks are whitespace, so the layout does not matter. The lesson's Tokens.java printed the same sum for five marks on one line and on two lines.

  11. Question 11 of 19 Before each nextInt(), a program runs while (in.hasNext() && !in.hasNextInt()) in.next();. What happens on the input 72 eighty 64?

    Choose one answer.

    Show the answer: Question 11 of 19

    Answer: It skips eighty, so the program reads 72 and then 64

    hasNextInt() looks at the next token without reading it, and next() reads a token whatever it is. Together they skip every token that is not a whole number, such as eighty, instead of failing on it.

  12. Question 12 of 19 On a computer whose format locale is German, what does new Scanner("3.5").hasNextDouble() return?

    Choose one answer.

    Show the answer: Question 12 of 19

    Answer: false, because the German decimal separator is a comma

    A Scanner starts with the computer's format locale and reads numbers in that locale's format. In de-DE the text 3,5 is a number and 3.5 is not, as LocaleNumbers.java showed. useLocale(Locale.ROOT) makes the reading the same everywhere.

  13. Question 13 of 19 A data file holds 100,000, meaning a hundred thousand. On a computer whose format locale is German, with no useLocale call, what does a Scanner read?

    Choose one answer.

    Show the answer: Question 13 of 19

    Answer: The double 100.0

    The output showed de-DE reading 100,000 as the double 100.0, while Locale.ROOT and en-IN read the int 100000: a silent error of a factor of a thousand. useLocale(Locale.ROOT) prevents it.

  14. Question 14 of 19 The input is 19 on one line and Asha Rao on the next. A program calls nextInt() and then nextLine(). What does nextLine() return?

    Choose one answer.

    Show the answer: Question 14 of 19

    Answer: An empty string

    nextInt() reads 19 and stops in front of the line break. nextLine() returns the rest of the current line, which is empty. Calling nextLine() once more, or reading every line with nextLine() and converting with parseInt, fixes it.

  15. Question 15 of 19 A menu program reads a choice with nextInt() and then commands with nextLine() in a loop. The first command always comes back empty. Which change fixes it and also lets a bad choice be reported as typed?

    Choose one answer.

    Show the answer: Question 15 of 19

    Answer: Read every line with nextLine() and convert the choice with Integer.parseInt(line.strip())

    Fix 2 of the lesson never mixes token reads and line reads: every line arrives whole, the number is converted with Integer.parseInt(line.strip()), and a line that is not a number can be reported exactly as it was typed.

  16. Question 16 of 19 A program reads its first line with IO.readln() and then creates new Scanner(System.in) for the rest. What can happen?

    Choose one answer.

    Show the answer: Question 16 of 19

    Answer: The Scanner misses input that IO.readln already buffered, without any error

    IO.readln reads ahead into a buffer of its own, and its documentation says any later use of System.in has unspecified behaviour. In the lesson's run the Scanner found no numbers in a small file, and 18,141 of 20,000 in a large one, starting with 859, the last three digits of 1859. Use one reader for all input.

  17. Question 17 of 19 A program reads a count with a BufferedReader and then the names that follow with IO.readln(). What do you expect?

    Choose one answer.

    Show the answer: Question 17 of 19

    Answer: IO.readln may find names missing, because the BufferedReader has already read ahead

    The rule does not depend on the order: every reader fetches more than it returns, so a second reader on the same System.in starts after the first one's buffer. One reader for all input avoids it.

  18. Question 18 of 19 Why is a Scanner slower than a BufferedReader on a million numbers?

    Choose one answer.

    Show the answer: Question 18 of 19

    Answer: It matches every token against regular expressions

    A Scanner matches every token against regular expressions, which costs time on large inputs. A BufferedReader returns whole lines, and the program cuts each line into numbers with split or a StringTokenizer.

  19. Question 19 of 19 An input of 1,000 numbers is read with a Scanner. Should you rewrite the reading with a BufferedReader?

    Choose one answer.

    Show the answer: Question 19 of 19

    Answer: No: at this size any reader is fast enough

    For a few lines typed at a keyboard, or a thousand numbers, the reader does not matter. A BufferedReader is worth its few extra lines for inputs of hundreds of thousands of numbers under a time limit.

Interview questions

Fresher · Why does nextLine() return an empty string right after nextInt(), and how do you fix it?

nextInt() reads only the digits of the number and stops in front of the line break that follows them. nextLine() returns the rest of the current line, and after a number at the end of a line that rest is empty, so it returns "" at once instead of waiting for the next line. There are two fixes. Call nextLine() once right after nextInt() to throw away the end of that line, or read every line with nextLine() (or IO.readln()) and convert the number with Integer.parseInt(line.strip()). The second is usually better: input arrives line by line, a bad line can be reported as it was typed, and the two reading styles are never mixed. The same trap exists with nextDouble() and next().

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to mid

    Your Java solution reads 200,000 lines of numbers with a Scanner and gets "time limit exceeded" on a judge, although its algorithm is O(n log n) and it passes every small test. How do you find out whether reading the input is the bottleneck, and what would you change?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A program reads a header line with IO.readln() and then wraps System.in in a Scanner for the data. With small test files the Scanner finds no data at all; with a large file the first few thousand records are missing and one value is wrong. Explain the cause, and how you would make the input code safe.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • IO.readln() hands over one line per call, minus its line break, and null at the end of input, so a loop that compares each result with null reads every line.
  • A line is text: convert it with Integer.parseInt(line.strip()) or Double.parseDouble(line), catch NumberFormatException, and check the range and Double.isFinite as separate steps.
  • A Scanner reads tokens across line breaks, with System.getProperty("stdin.encoding") for the bytes and useLocale(Locale.ROOT) for data written with a decimal point.
  • After nextInt() the line break is still waiting: discard it with one nextLine(), or read whole lines only.
  • One reader owns System.in: mixing IO.readln with a Scanner silently lost 1,859 numbers and read one wrong.
  • For very large inputs, a BufferedReader that cuts each line with split or a StringTokenizer read a million numbers several times faster than a Scanner.

Terms in this lesson

end of input
The point where standard input has no characters left: a file has been read to its end, or the user pressed Ctrl-D (macOS, Linux) or Ctrl-Z and Enter (Windows). IO.readln then returns null.
standard input
The stream a program reads its input from, System.in in Java. It is the keyboard of the terminal unless the shell connects a file with < or the output of another command with |.
token
A piece of input between two stretches of whitespace (spaces, tabs or line breaks), such as 72 or eighty. A Scanner reads one token with next(), or converts it with nextInt() or nextDouble().

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.