Skip to content
Ameen Abozaid
PublishedBEG-011-L02

The nextInt / nextLine trap

  • Lesson 2 of 6
  • 11 min read
  • Beginner
On This Lesson 11 topics

Lesson Overview

In the last lesson you read text and numbers with Scanner. Each program worked. Now put the two together in the most natural order: ask for an age (a number), then ask for a full name (a line). Run it, type your age, and watch what happens: the program never lets you type the name. It prints an empty name and finishes.

This is the best-known Scanner surprise, and almost every Java beginner hits it. Nothing is broken in Java. The program does exactly what it was told; what it was told is just not what you thought. Once you understand where the Enter key goes when you press it, the problem becomes obvious and the fix is one line.

Why this matters: the cause is a general fact about input, not just about Scanner. Input arrives as a stream of characters in order, a reader consumes it piece by piece, and what a method does not consume stays there for the next method. You will meet the same idea with files, sockets, and request bodies.

This lesson builds directly on "Reading input with Scanner".

Learning Objectives

By the end of this lesson you will be able to:

  • Describe input as a stream of characters, including the invisible line break.
  • Explain exactly what nextInt() consumes and what it leaves behind.
  • Explain why a nextLine() that follows nextInt() returns an empty string.
  • Fix the trap with one extra nextLine() call.
  • Avoid the trap in two other ways: reorder the questions, or read every answer with nextLine().
  • Recognise the same symptom when mixing nextDouble() or next() with nextLine().

Written Explanation

The keyboard is a stream

When you type 30 and press Enter, the program does not receive a number. It receives characters, one after another: 3, 0, and then a line break that represents the Enter key. (On Windows the line break is two characters, and on Linux and macOS one, but Scanner treats them all as a line ending, so we write \n for "the line break".)

After you type 30, Enter, the input waiting to be read looks like this:

text
30\n

Think of it as a ribbon of paper coming out of a machine. A read position marks where the reader is. Each Scanner method starts at the read position and moves it forward.

What nextInt() consumes

nextInt() skips any whitespace in front of the number, reads the token 30, and stops right after the last digit. It does not touch what follows:

text
30\n
  ^ read position is here, before the \n

The line break is still in the input. Nobody asked nextInt() to remove it, and it does not.

What nextLine() consumes

nextLine() has a different job. The Javadoc says it advances the scanner past the current line and returns the input that was skipped. In plain words: it returns everything from the read position up to the next line break, and then moves past the line break.

If the read position is right in front of a \n, "everything up to the line break" is nothing at all. So nextLine() returns the empty string "" immediately, without waiting for the user, and the read position moves past the \n.

That is the whole trap. Step by step for the program in the example below:

  1. nextInt() reads 30 and leaves \n behind.
  2. The prompt Full name: is printed.
  3. nextLine() finds the leftover \n, returns "", and the program carries on.
  4. The user never gets the chance to type the name, because the scanner already had a line to give.

Rule: a nextInt(), nextDouble(), or next() reads a token and leaves the end of the line. A nextLine() right after one of them reads that leftover.

Fix 1: throw the leftover away

Call nextLine() once, immediately after the number, and ignore what it returns:

java
int age = in.nextInt();
in.nextLine();                 // consumes the rest of the age line
String name = in.nextLine();   // now reads the real name

You do not store the result. The call exists only to move the read position past the leftover line break. A short comment explaining the purpose is good style, because a bare in.nextLine(); looks like a mistake to a reader.

If the user types extra text after the number (30 years), that extra text is also part of the leftover and the extra nextLine() discards it too. That is useful: it keeps the next question clean.

Fix 2: change the order

The trap needs a number followed by a line. A line followed by a number is safe, because nextLine() consumes its own line break. In a program with several questions, putting the line questions first and the number questions last avoids the problem without any extra call. This is not always possible, though; a form often has to ask in a fixed order.

Fix 3: read every answer as a line

A third approach is to read everything with nextLine() and convert the text to numbers yourself. Then every read consumes its own line break and no leftover exists. The conversion method is the topic of the next lesson, Integer.parseInt. Many programmers prefer this approach for long forms, because it behaves the same for every question.

ApproachExtra codeBest when
Extra nextLine() after each numberOne line per numberA few numbers mixed with lines
Reorder questionsNoneOrder is free
Read all as lines, then convertA conversion per numberLong forms; the next lesson

The same trap with other methods

The trap appears after any method that reads a token: next(), nextDouble(), nextBoolean(), and so on. It does not matter whether the number comes first or you read several numbers in a row. Only the nextLine() that follows a token read is affected. Two number reads in a row are fine, because both skip whitespace, which includes line breaks, in front of the token.

Examples

Example 1: the bug (simple)

java
import java.util.Scanner;

public class Trap {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Age: ");
        int age = in.nextInt();
        System.out.print("Full name: ");
        String name = in.nextLine();
        System.out.println("[" + name + "] is " + age + " years old.");
    }
}

With the user typing 30 and pressing Enter, the program runs straight through:

text
Age: 30
Full name: [] is 30 years old.

The user never typed a name. The square brackets in the output make the empty string visible: always print values inside markers like [ and ] while debugging, because an empty or space-filled string is invisible otherwise.

Example 2: the fix (practical)

java
import java.util.Scanner;

public class Fixed {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Age: ");
        int age = in.nextInt();
        in.nextLine();                      // throw away the rest of the age line
        System.out.print("Full name: ");
        String name = in.nextLine();
        System.out.println("[" + name + "] is " + age + " years old.");
    }
}
text
Age: 30
Full name: Ana Smith
[Ana Smith] is 30 years old.

The only change is the line with the comment. The extra nextLine() consumed the leftover \n, so the next nextLine() had to wait for real input.

Example 3: a hidden leftover (realistic)

The leftover is not always empty. Suppose a form reads two numbers on one line and then a note:

java
import java.util.Scanner;

public class Mixed {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Two numbers: ");
        int a = in.nextInt();
        double b = in.nextDouble();
        System.out.println("a=" + a + " b=" + b);
        System.out.print("Note: ");
        String note = in.nextLine();
        System.out.println("note=[" + note + "]");
    }
}

If the user types 7 2.5 and Enter, the note comes back empty again:

text
Two numbers: 7 2.5
a=7 b=2.5
Note: note=[]

Now suppose a careless user types all three things on the first line, 7 2.5 hello there. The "note" is the rest of that line, including the space in front of hello:

text
Two numbers: 7 2.5 hello there
a=7 b=2.5
Note: note=[ hello there]

The program has not waited at all: the scanner had unread text on the current line, so nextLine() returned it at once. This is a real-world version of the trap, and the same extra nextLine() after the last number (or a .trim() on the result) is the cure. It also shows why you should never assume the leftover is exactly an empty line.

Backend Insight

Every protocol that reads text deals with this boundary problem: where does one piece of data end and the next begin? Web servers read HTTP requests as a stream, and the parser must consume exactly the right number of characters. A parser that leaves one character unread, or reads one too many, corrupts everything after it, in the same way our nextLine() read the leftover.

Two habits carry over from this lesson to server code:

  • Know what each read consumes. A reading method defines where it starts and where it stops. Whoever reads next inherits the leftover.
  • Make the bug visible. Printing [ and ] around a value, or logging the raw input, is how you find a stray space or newline. Production logs for request handling use the same technique.

Common Mistakes

Mistake 1: Reading a line right after a number

  • Incorrect: nextInt() followed by nextLine() for a name.
  • Correct: nextInt(), then one throw-away nextLine(), then the real nextLine().

Mistake 2: Adding the extra nextLine() where it is not needed

If the program reads a line first and then a number, the extra call is not needed, and it would swallow the user's next input. Place it only after a token read that is followed by a line read.

Mistake 3: Calling the extra nextLine() after the wrong read

The extra call must come directly after the last number on that line, and before the next line read. Putting it before the number does nothing useful.

Mistake 4: Blaming the keyboard or Java

"Java skipped my question" is a misunderstanding. The input stream held a line break, and nextLine() correctly read it. Print the result inside brackets to see what you got.

Mistake 5: Assuming the leftover is always empty

If the user types extra text after the number, the leftover is not empty. The throw-away call discards it, which is usually what you want.

Exercises

Try each exercise yourself before opening the solutions.

Level A: Foundation

A1. After the user types 25 and Enter, what unread characters remain once nextInt() has finished?

Show solution A1

A1. Only the line break (\n). nextInt() consumed the digits 2 and 5 and stopped.

A2. Which of these sequences has the trap: (a) nextLine(), nextInt(); (b) nextInt(), nextLine(); (c) nextInt(), nextInt(); (d) nextDouble(), nextLine()?

Show solution A2

A2. (b) and (d). In (a) the line comes first, so it consumes its own break. In (c) both reads skip whitespace in front of the token.

A3. What does nextLine() return when the read position is directly before a line break?

Show solution A3

A3. The empty string "". It does not wait for the user, because a line (an empty one) is already available.

Level B: Application

B1. This program should ask for a city and then a population, then a country. It has one bug. Find it and fix it.

java
System.out.print("Population: ");
int pop = in.nextInt();
System.out.print("Country: ");
String country = in.nextLine();
Show solution B1

B1. nextInt() leaves the line break behind, so the country comes back empty. Fix: add in.nextLine(); between the nextInt() and the country read:

java
int pop = in.nextInt();
in.nextLine();                 // discard the leftover line break
System.out.print("Country: ");
String country = in.nextLine();

B2. Reorder these questions so that the program needs no extra nextLine(): age (number), full name (line), height (decimal), street address (line).

Show solution B2

B2. Lines first, numbers last: full name, street address, age, height. After the last number there is nothing more to read, so nothing is left to cause trouble. (Reading the name before the age also works, if you need to ask age second, but then the throw-away call returns.)

B3. A friend added in.nextLine(); before every nextInt() "to be safe". Explain what happens at the first prompt, and why that is a bug.

Show solution B3

B3. The first nextLine() is called with no leftover in front of it, so it waits for the user to type a whole line, and the program appears to ask for the number twice. The extra call belongs after a number read and before a line read, not before every number.

Level C: Challenge

C1. Write a program that asks for a quantity (int), a product name (line), and a price (double), then prints 3 x Pen at 1.5. Use Fix 1 correctly. Where exactly does each throw-away call go?

Show solution C1

C1.

java
System.out.print("Quantity: ");
int qty = in.nextInt();
in.nextLine();                         // after the number, before the line
System.out.print("Product: ");
String name = in.nextLine();           // a line, consumes its own break
System.out.print("Price: ");
double price = in.nextDouble();        // last read; nothing follows it
System.out.println(qty + " x " + name + " at " + price);

Only one throw-away call is needed, between the number and the line. The price read is last and is followed by no line read. (Not compiled separately; it uses the same calls as the compiled examples.)

C2. The user types 42 abc and Enter in response to nextInt(), followed by a nextLine() whose result is printed in brackets. What is printed, and why?

Show solution C2

C2. The nextInt() reads 42, and the leftover is abc plus the line break. nextLine() returns abc (with a leading space), so [ abc] is printed. The program does not wait. This is the same behaviour as Example 3.

Mini Challenge

Build Pet registration. The program asks, in this order: the pet's name (line), age in years (int), the owner's full name (line), and weight in kg (double). Print a one-line summary. Run it with the throw-away call removed first and note which answer comes back wrong. Then add the one needed line.

Check your work: you can say which answer was skipped and why, and the final version has exactly one throw-away nextLine().

Summary & Next Lesson

Key takeaways

  • Input is a stream of characters, and the Enter key is a line break character in it.
  • nextInt(), nextDouble(), and next() read a token and leave the rest of the line, including the line break.
  • A nextLine() that follows reads that leftover and returns it, often as an empty string.
  • Fix: one throw-away in.nextLine(); after the number. Alternatives: ask line questions first, or read everything as lines.
  • Print values inside brackets while debugging so empty and space-filled strings become visible.

Next lesson

Next is "Parsing strings into numbers". You will convert text into numbers with Integer.parseInt and Double.parseDouble, which is the third fix above, and see what happens when the text is not a number.

Self-check

  1. What character does nextInt() leave in the input?
  2. Why does the following nextLine() return an empty string?
  3. What is the one-line fix?
  4. Is the trap present when nextLine() comes before nextInt()?
  5. Name one other method that leaves the line break behind.
Show answers
  1. The line break from the Enter key.
  2. The read position is right before the leftover line break, so the "rest of the line" is empty.
  3. Call in.nextLine(); once right after the number read, ignoring the result.
  4. No. nextLine() consumes its own line break, so the number read after it starts clean.
  5. next() or nextDouble() (any token reader).

References

  • Oracle, Java SE 21 API, Scanner. Supports tokens separated by whitespace by default, nextLine() returning the rest of the current line and advancing past it, and number methods reading only a token.
  • All code in this lesson was compiled and run with JDK 21; the quoted program output is real. The platform detail about the line break being one or two characters is general knowledge not checked against a page for this lesson.

Practice

Apply this lesson with the module's lab, exercises and quiz.

Lab and exercises Quiz

Marking a lesson complete is optional and you can undo it any time. Your progress stays in this browser.

Continue to next lesson

Type to search levels, phases, modules and lessons.