DEV Community

Cover image for Understanding Java's Scanner: Why Mixing nextInt() and nextLine() Breaks Your Code
Aditya Sinha
Aditya Sinha

Posted on • Edited on

Understanding Java's Scanner: Why Mixing nextInt() and nextLine() Breaks Your Code

Almost every java learner encounters this problem at some point.

You write a simple program that asks for an age (an int) and then a name (a String). You run it, type an age, press Enter, and before you've typed a single letter of the name, the program has already finished running.

It feels like a glitch.

But, in reality, you have encountered what developers call the Scanner buffer issue. To keep things simple for us beginners, I like to call it the nextLine() issue.


Problem

Code That “Should” Work

Take a look at this snippet.

Scanner sc = new Scanner(System.in);

System.out.println("Enter an age");
int age = sc.nextInt();
// Example input: 25

System.out.println("Enter a name");
String name = sc.nextLine();
// Example input: Ahi

System.out.println("Name: " + name);
System.out.println("Age: " + age);
Enter fullscreen mode Exit fullscreen mode

You might expect the following interaction:

Enter an age
25
Enter a name
Ahi
Enter fullscreen mode Exit fullscreen mode

Sadly, it is not that simple.

When you type 25 and press Enter. The program finishes before you can even type the name. Therefore, the actual output is:

Name:
Age: 25
Enter fullscreen mode Exit fullscreen mode

Why did this happen? Let’s investigate.

Important note:

I’ve included a quick glossary at the bottom to help you with unfamiliar terms.


Investigation

What Happens Inside?

When you use Scanner class to read input from the keyboard, every key you press is first stored inside the input buffer as a character.

The characters remain in the buffer until:

  • The program consumes them (that is, takes them out of the buffer) using methods like next(), nextInt(), nextLine(), or

  • The program terminates.

The Scanner class reads input using two strategies:

  • Token-based parsing

  • Line-based parsing

Every character inside the buffer is examined one by one.

Depending on the parsing rules being applied, a character will either be:

  • Consumed and returned (removed from the buffer and included in the result)

  • Consumed and discarded (removed from the buffer but not returned as part of the result)

  • Left in the buffer (to be processed later)


Token-Based Parsing

In this approach, input is divided into tokens and one token is returned at a time.

Rules:

  1. Leading delimiters are consumed and discarded.

  2. From the first non-delimiter character, characters are consumed until a delimiter is detected.

  3. The detected delimiter is left in the buffer.

  4. The consumed characters are returned to the program as one token.

Methods that use this approach:

  • next()

  • nextInt()

  • nextDouble()

  • nextFloat()

  • nextLong()

  • nextBoolean()


Line-Based Parsing

In this approach, input is read as an entire line.

Rules:

  1. Characters are consumed continuously, including whitespace characters (spaces and tabs).

  2. Reading continues until a line terminator ('\n') is encountered.

  3. The line terminator ('\n') is consumed and discarded.

  4. All characters before the line terminator are returned as a single String.

Method that uses this approach:

  • nextLine()


Observation

Understanding the Behaviour

Now that we understand how input is read, let us trace the execution of our “failing” code to identify where things went wrong.

Step 1: Input Entry

When the program runs, the terminal displays:

Enter an age
Enter fullscreen mode Exit fullscreen mode

You type 25 and press Enter.

Buffer Status: ['2'] ['5'] ['\n']


Step 2: nextInt() Executes

int age = sc.nextInt();
Enter fullscreen mode Exit fullscreen mode

Following the rules of token-based parsing, nextInt():

  • Begins reading from the buffer

  • Consumes '2' and '5' (non-delimiter characters)

  • Encounters '\n', which is a delimiter

  • Stops reading but does not consume the delimiter

  • Parses the token "25" into the integer value 25

  • Returns 25 to the program

int age = 25;
Enter fullscreen mode Exit fullscreen mode

Buffer Status: ['\n']

The line feed remains in the buffer.


Step 3: Prompt Appears

The terminal now shows:

Enter an age
25
Enter a name
Enter fullscreen mode Exit fullscreen mode

Misconception: You might expect the program to pause here and wait for you to type Ahi.

Reality: The program pauses only if the buffer is empty.


Step 4: nextLine() Executes

String name = sc.nextLine();
Enter fullscreen mode Exit fullscreen mode

Following the rules of line-based parsing, nextLine():

  • Checks the buffer

  • Immediately detects '\n'

  • Consumes and discards the line feed

  • Returns everything before '\n'

There were no characters before it.

Therefore, it returns an empty string.

String name = "";
Enter fullscreen mode Exit fullscreen mode

Step 5: Final Output

The program executes:

System.out.println("Name: " + name);
System.out.println("Age: " + age);
Enter fullscreen mode Exit fullscreen mode

The output is:

Name:
Age: 25
Enter fullscreen mode Exit fullscreen mode

Solution

Now you understand where the problem occurred and why. Let us fix it.

There are several ways to solve this; we will discuss a few.

1. The Quick Fix

The most straightforward solution is to consume the leftover line feed.

Add an extra nextLine() immediately after nextInt() to clear the buffer.

System.out.println("Enter an age");
int age = sc.nextInt(); 

sc.nextLine(); // Consumes and discards the leftover '\n'

System.out.println("Enter a name");
String name = sc.nextLine();
Enter fullscreen mode Exit fullscreen mode

Why it Works:

  • nextInt() leaves the line feed character ('\n') in the input buffer.

  • The additional nextLine() consumes that '\n' and removes it.

  • Now, when the second nextLine() executes, the buffer is clean, so the program waits for your name input.


2. The Professional Approach

Avoid mixing token-based and line-based parsing.

Instead, read all input using nextLine() and convert numeric values explicitly using parsing methods such as Integer.parseInt(). This method takes a numeric string (for example, "25") and converts it into a primitive int value (25).

System.out.println("Enter an age:");
int age = Integer.parseInt(sc.nextLine()); 

System.out.println("Enter a name:");
String name = sc.nextLine();
Enter fullscreen mode Exit fullscreen mode

Why it Works:

  • nextLine() consumes the line feed character each time it reads input, so no delimiters remain in the buffer.

  • Parsing explicitly using methods such as Integer.parseInt() gives you greater control over input handling.

Worth knowing:

if the input isn't a valid number, Integer.parseInt() throws a NumberFormatException. In a real application, you would typically validate the input before parsing it.

Other Parsing Methods:

The same pattern applies to other numeric types:

  • Double.parseDouble()

  • Float.parseFloat()

  • Long.parseLong()

  • Boolean.parseBoolean()


3. The Duct Tape Fix

You can reverse the order of the inputs and avoid the issue.

If you read the String first and the int afterwards, the problem seems as though it never occurred.

System.out.println("Enter a name");
String name = sc.nextLine();

System.out.println("Enter an age");
int age = sc.nextInt();
Enter fullscreen mode Exit fullscreen mode

Why This is Wrong:

nextInt() still leaves '\n' in the input buffer.

If the program later requires another call to nextLine(), the same issue will immediately reappear.


Conclusion

Now you understand the whys, the hows, the dos and the don’ts.

In Java, nothing is broken. The behaviour is defined, the rules are strict, and the machine is consistent. Use that consistency to your advantage rather than fighting against it.

Try the following example yourself:

Scanner sc = new Scanner(System.in);

System.out.println("Enter your full name:");
String firstName = sc.next();
String lastName = sc.next();

System.out.println("Hello " + firstName + " " + lastName);
Enter fullscreen mode Exit fullscreen mode

Enter your own name, for example:

Aditya Sinha
Enter fullscreen mode Exit fullscreen mode

The output will be:

Hello Aditya Sinha
Enter fullscreen mode Exit fullscreen mode

Pause and think.

  • Why does this work?

  • How does next() decide where to stop reading?

  • What remains in the input buffer afterwards?

  • What happens if the name has more than two parts?


Glossary

Short and Simple

Buffer

When data is being transferred from a source (Point A) to a destination (Point B), it is temporarily stored in a small memory area between them called a buffer. It serves as a waiting room for data and typically follows the FIFO (First In, First Out) principle.

Input Buffer:

Source: Keyboard

Destination: Java program

However, internally, the data passes through multiple layers before reaching the Java program.


Token

A token is a continuous sequence of non-delimiter characters.

Token formation is the internal act of grouping characters together until a delimiter is found.

Input buffer:

['2']['5'][' ']['A']['h']['i']
Enter fullscreen mode Exit fullscreen mode

Tokens formed:

"25"
"Ahi"
Enter fullscreen mode Exit fullscreen mode

Parsing

Theoretical view.

When you type 25 through the keyboard, the computer receives (represented internally in binary form):

'2'  -> ASCII value 50  
'5'  -> ASCII value 53
'\n' -> ASCII value 10
Enter fullscreen mode Exit fullscreen mode

At this stage, the computer does not recognise the integer 25.

It only sees the sequence of characters '2', '5', and '\n'.

Inside a nextInt() method of the Scanner class:

Token Formation occurs:

['2','5','\n'] -> "25"
Enter fullscreen mode Exit fullscreen mode

A String token "25" is formed.

At this point, it is still text, not a numeric value.

The Actual Parsing:

Parsing now occurs inside nextInt().

The String "25" is:

  • Checked to ensure it is a valid integer

  • Converted into the numeric value 25

"25"  -> before parsing (String)
25    -> after parsing (int)
Enter fullscreen mode Exit fullscreen mode

The integer value is then returned to the program.

Parsing here simply means converting characters into a meaningful data type.

This is different from compiler parsing, which involves analysing the grammatical structure of an entire program.

In both cases, however, the core idea remains the same: Interpreting input according to defined rules.


Whitespace Character

A whitespace character has no visible symbol. It appears as blank space and is used to create horizontal or vertical separation between visible characters.

A few examples:

  • ' ' (space)

  • '\t' (tab)

  • '\n' (line feed)

Use:

System.out.println("Name" + " " + "Age" + "\n" + "Ahi" + "\t" + "25");
Enter fullscreen mode Exit fullscreen mode

Output:

Name Age
Ahi     25
Enter fullscreen mode Exit fullscreen mode

Escape Sequence Character

An escape sequence is a special character representation used inside a string. It always starts with a backslash (\), which acts as a signal to the compiler to "escape" its normal rules of treating a character.

These characters cannot be typed directly inside a string because it has special meaning in Java.

For example, double quotes " are used to mark the beginning and end of a string.

If you try to use them directly inside a string, the compiler gets confused.

A few escape sequence characters:

  • \n (Line Feed)

  • \t (Tab)

  • \" (Double Quote)

If you want to print text inside double quotes, you have to use escape sequence.

System.out.println("He said, \"Hello!\""); 
Enter fullscreen mode Exit fullscreen mode

Without \", Java would think the string ends before Hello!, causing a compilation error.

Output:

He said, "Hello!"
Enter fullscreen mode Exit fullscreen mode

Escape sequences and whitespace characters are not the same thing.

While whitespace is any character that creates a blank space, escape sequence characters are not always blank spaces.

  • \"

    Escape sequence

    Not whitespace

  • \n

    Escape sequence

    Also whitespace

  • ' ' (space)

    Whitespace

    Not an escape sequence


Delimiter

In the context of Scanner and input processing in Java, a delimiter is a character or pattern used to separate input into smaller pieces called tokens. It marks where one token ends and the next begins like a boundary.

By default, Scanner uses whitespace characters as delimiters.

When you type:

25 Ahi
Enter fullscreen mode Exit fullscreen mode

The space acts as a delimiter, and Scanner sees two tokens:

[25] [Ahi]
Enter fullscreen mode Exit fullscreen mode

You can even change it using useDelimiter() method:

sc.useDelimiter(",");
Enter fullscreen mode Exit fullscreen mode

Now the comma becomes the delimiter.

If the input is:

25,Ahi
Enter fullscreen mode Exit fullscreen mode

The tokens will be:

[25] [Ahi]
Enter fullscreen mode Exit fullscreen mode

Line terminator

A line terminator is a kind of whitespace characters (also an escape sequence character) that is used to move the cursor to a new line.

Few examples:

  • ‘\n’ (Line feed)

  • '\r' (Carriage return)

System.out.println("Hello\nWorld");
Enter fullscreen mode Exit fullscreen mode

Output:

Hello
World
Enter fullscreen mode Exit fullscreen mode

Note

Everything above is a great mental model for understanding why this bug happens, but it's still a simplified picture. Under the hood, Scanner doesn't actually go character by character. It uses regex pattern matching to find tokens in the buffer. If you're curious to see the real thing, here's where to look:


Let's Connect!

If you found this helpful, or have any doubts or queries, feel free to reach out via the links below:

Top comments (0)