Course topics

By WebNest Studio Engineering Team

Java - Core Tutorial

Scanner and Reading User Input

Reading input typed by a user while a program is running is one of the most common tasks in introductory Java programs, and the Scanner class (in java.util) is the standard, beginner-friendly tool for it. Scanner can read from System.in (the keyboard), from a file, or from a String, and it provides convenient typed methods like nextInt(), nextDouble(), and nextLine() that parse tokens directly into the requested type.

Scanner is easy to use but has one very well-known pitfall around mixing token-based reads with line-based reads, and for performance-sensitive or purely line-based input, BufferedReader is often a better fit.

Why it matters

Reading input is the first interactive thing most programs do, and almost everyone who uses Scanner meets the same bug: a name that comes back empty after a number was read. Understanding why it happens takes a few minutes and saves hours, in practice programs and in coding tests alike.

Reading Different Types with Scanner

A Scanner wrapping System.in is created once with new Scanner(System.in) and then reused for the whole program. Methods like nextInt(), nextLong(), nextDouble(), and next() (a single whitespace-delimited token) read and parse exactly one token, leaving the cursor positioned right after that token — including the newline character the user typed to submit it, which is not consumed. nextLine(), by contrast, reads everything up to and including the next newline character, returning it as a String.

The Leftover Newline Bug

The most common Scanner mistake happens when a numeric read like nextInt() is immediately followed by nextLine(). Because nextInt() only consumes the digits of the number and stops — it does not consume the newline character left in the input buffer after the user pressed Enter — the very next nextLine() call immediately reads that leftover empty newline instead of waiting for new input, silently skipping the line you intended the user to type. The fix is to insert an extra, throwaway scanner.nextLine() call right after the numeric read, specifically to consume that leftover newline before reading the next real line.

BufferedReader as a Faster, Line-Based Alternative

BufferedReader wrapping an InputStreamReader over System.in reads input purely as text lines via readLine(), with no automatic type parsing — you convert Strings to numbers yourself with methods like Integer.parseInt(). Because it reads in larger buffered chunks rather than token-by-token, BufferedReader is noticeably faster for programs that read a large volume of input (a common concern in competitive programming), and since it only ever deals in whole lines, it sidesteps the leftover-newline confusion entirely. The trade-off is slightly more code, since you lose Scanner's built-in numeric parsing convenience, and BufferedReader's readLine() throws a checked IOException that Scanner's methods do not.

Closing Scanner and System.in

Scanner implements Closeable, and calling scanner.close() when a program is finished with input is good practice. However, closing a Scanner that wraps System.in also closes the underlying System.in stream itself — if any other code later tries to read from System.in again (including creating a second Scanner over it) in the same program run, that read will fail. For this reason, most programs create exactly one Scanner over System.in for their entire lifetime and close it once, right before exiting, rather than opening and closing several Scanners over System.in in the same run.

Examples

The classic nextInt()/nextLine() leftover newline bug and its fix

Java
import java.util.Scanner;

public class ScannerBugDemo {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Enter your age: ");
        int age = scanner.nextInt();
        scanner.nextLine(); // consumes the leftover newline left by nextInt()

        System.out.print("Enter your name: ");
        String name = scanner.nextLine();

        System.out.println("Name: " + name + ", Age: " + age);
        scanner.close();
    }
}

// Sample input typed by the user:
// 28
// Asha
Output
Enter your age: Enter your name: Name: Asha, Age: 28

Reading a line of input with BufferedReader instead of Scanner

Java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Enter a city: ");
        String city = reader.readLine();

        System.out.println("You entered: " + city);
    }
}

// Sample input typed by the user:
// Mumbai
Output
Enter a city: You entered: Mumbai

Common Mistakes

  • Calling nextInt() (or nextDouble()) immediately followed by nextLine() without an extra nextLine() to consume the leftover newline, causing the following line-read to appear to be skipped.
  • Creating and closing multiple Scanner objects over System.in in the same program — closing one closes the underlying System.in stream for the rest of the program.
  • Forgetting that Scanner's next() reads only a single whitespace-delimited token, not a whole line — a multi-word name typed by the user gets truncated at the first space.
  • Choosing Scanner for very large or performance-critical input processing where BufferedReader's lower overhead would matter.

Exercise

The input contains an age on the first line and a full name on the second. As written, the program prints an empty name because nextLine() reads the rest of the first line. Fix it. The Scanner reads from a string here so the result is the same on every run; the fix is identical for System.in.

Expected output: Asha Rao, 25

Java · starter code
import java.util.Scanner;

public class ReadAgeAndName {
    public static void main(String[] args) {
        Scanner scanner = new Scanner("25\nAsha Rao");

        int age = scanner.nextInt();
        // TODO: the line break after 25 is still unread at this point
        String name = scanner.nextLine();

        System.out.println(name + ", " + age);
    }
}
Show hints
  • nextInt() reads the digits and stops before the line break.
  • Add one scanner.nextLine() call after nextInt() to consume the rest of that line.
Show solution
Java · solution
import java.util.Scanner;

public class ReadAgeAndName {
    public static void main(String[] args) {
        Scanner scanner = new Scanner("25\nAsha Rao");

        int age = scanner.nextInt();
        scanner.nextLine(); // consume the line break left after the number
        String name = scanner.nextLine();

        System.out.println(name + ", " + age); // Asha Rao, 25
    }
}

Quick quiz

1. The user types Asha Rao and presses Enter. What does scanner.next() return?

  • A. Asha Rao
  • B. An empty string
  • C. Rao
  • D. Asha
Show answer

D. next() reads one token, up to the next whitespace. nextLine() reads the whole line.

2. What does nextInt() throw when the next token is not a number?

  • A. InputMismatchException
  • B. NumberFormatException
  • C. IOException
  • D. It returns 0
Show answer

A. Check with hasNextInt() first, or catch InputMismatchException.

3. What is the effect of closing a Scanner that wraps System.in?

  • A. Nothing
  • B. The program exits
  • C. System.in is closed as well and cannot be read again in that program
  • D. The input buffer is cleared
Show answer

C. Closing the Scanner closes the stream it wraps, so one Scanner is normally used for the whole program.

Interview questions

What is the difference between Scanner and BufferedReader?

Show answer

Scanner parses input into tokens and types, with methods such as nextInt() and nextDouble(), and does not throw checked exceptions. BufferedReader only reads characters and lines, so numbers must be parsed by hand and IOException must be handled, but it is faster for large input because it does no parsing.

Why does nextLine() return an empty string after nextInt()?

Show answer

nextInt() reads only the digits and leaves the line break in the input. nextLine() reads up to the next line break, which is the one left behind, so it returns an empty string. The fix is an extra nextLine() after nextInt(), or reading every line with nextLine() and converting with Integer.parseInt.

Key Points to Remember

  • Scanner provides typed reads (nextInt, nextDouble, next, nextLine) directly from System.in, a file, or a String.
  • nextInt()/nextDouble()/next() leave the trailing newline in the buffer; a following nextLine() call reads that leftover newline unless it is consumed first.
  • BufferedReader.readLine() reads whole lines faster and avoids the leftover-newline issue, at the cost of manual parsing and a checked IOException.
  • Closing a Scanner built on System.in also closes System.in itself, so most programs use a single Scanner instance for the whole run.

Practice in the playground

Write and run your own code for this topic, or start from the exercise or an example. Runs plain Java 17. Frameworks such as Spring, and databases, are not available here. Your code for each topic is kept in this browser.

Run the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

WebNest Studio

Written by

WebNest Studio Engineering Team

Practical lessons from developers working with Java, Python, React, databases and production systems.

Led by Vansh Duggal, Founder, WebNest Studio · Full-stack & software engineering