Java Scanner Handbook

1. Quick Summary

Scanner is a simple text scanner that can parse primitive types and strings using regular expressions. It breaks its input into tokens using a delimiter pattern (default is whitespace).

  • Package: java.util.Scanner

  • Key Feature: Easy parsing of primitives (int, double, etc.) without manual Integer.parseInt().

  • Performance: Slower than BufferedReader due to regex parsing logic.

  • Thread Safety: Not thread-safe.

2. Common Constructors

// 1. Reading from Console (Standard Input)
Scanner sc = new Scanner(System.in);

// 2. Reading from a File
Scanner sc = new Scanner(new File("input.txt"));

// 3. Reading from a String (Simulating input)
Scanner sc = new Scanner("10 20 30");

3. Essential Methods Cheat Sheet

Method

Return Type

Description

next()

String

Reads the next token (word) up to whitespace.

nextLine()

String

Reads the entire remaining line (including spaces).

nextInt()

int

Scans the next token as an int.

nextDouble()

double

Scans the next token as a double.

hasNext()

boolean

Checks if there is another token.

hasNextInt()

boolean

Checks if the next token is a valid integer (useful for validation).

useDelimiter(pattern)

Scanner

Changes the separator (e.g., to "," for CSV).

4. The "nextLine()" Trap (CRITICAL)

A very common bug occurs when you mix next()/nextInt() with nextLine().

The Problem:nextInt() reads the number but leaves the newline character (\n) in the buffer. The subsequent nextLine() reads that leftover newline and consumes it immediately, appearing to skip input.

The Fix:Fire an extra nextLine() to consume the leftover newline.

int age = sc.nextInt();
sc.nextLine(); // Consume the leftover newline
String name = sc.nextLine(); // Now works as expected

5. Scanner vs. BufferedReader

Feature

Scanner

BufferedReader

Parsing

Built-in (nextInt, nextBoolean)

Manual (Integer.parseInt)

Buffer Size

Small (1KB)

Large (8KB)

Delimiter

Configurable (Regex)

Strictly Line-based

Exceptions

Hides IOException

Throws IOException

Best For

Console input, Parsing structured text

Reading massive files, Network streams

6. Implementation Tips

  1. Input Validation: Always use hasNextInt() before nextInt() to prevent InputMismatchException if the user types "abc" instead of "123".

  2. Closing: Always close Scanners attached to Files. Be careful closing System.in: closing it prevents your application from reading from the console again for its entire lifetime.

import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
/**
* A comprehensive demonstration of Scanner usages.
* Includes:
* 1. Handling the "nextLine" trap.
* 2. Input validation (preventing crashes).
* 3. Reading from a file.
* 4. Using custom delimiters (CSV parsing).
*/
public class ScannerExamples {
public static void main(String[] args) {
// SETUP: Create a dummy file for the demonstration
createDummyFile("scores.txt");
System.out.println("=== 1. The Common 'nextLine' Trap ===");
demonstrateTrap();
System.out.println("\n=== 2. Input Validation (Robust Input) ===");
// Uncomment to run interactively, commented out for automated demo flow
// validateInputExample();
System.out.println("(Skipped interactive demo to keep output clean)");
System.out.println("\n=== 3. Reading from File ===");
readFromFile("scores.txt");
System.out.println("\n=== 4. Custom Delimiters (CSV Parsing) ===");
parseCSVString();
}
/**
* Pattern 1: Solving the problem where nextInt() leaves a newline character
* that causes the following nextLine() to be skipped.
*/
private static void demonstrateTrap() {
String input = "25\nJohn Doe"; // Simulated user input: Age then Name
Scanner sc = new Scanner(input);
System.out.println("Input Stream: " + input.replace("\n", "\\n"));
// Step 1: Read number
int age = sc.nextInt();
System.out.println("Read Age: " + age);
// Step 2: THE FIX
// If we don't do this, 'name' will be empty because it reads the leftover \n
sc.nextLine();
System.out.println("[Log] Consumed leftover newline");
// Step 3: Read Line
String name = sc.nextLine();
System.out.println("Read Name: " + name);

sc.close();
}
/**
* Pattern 2: Reading from a file safely.
* Note: Unlike BufferedReader, Scanner doesn't throw checked IOExceptions
* everywhere, but the constructor does.
*/
private static void readFromFile(String filename) {
try {
File file = new File(filename);
Scanner fileScanner = new Scanner(file);

while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine();
System.out.println("File Line: " + line);
}

fileScanner.close();
} catch (FileNotFoundException e) {
System.err.println("File not found: " + e.getMessage());
}
}
/**
* Pattern 3: Using delimiters to parse specific formats (like CSV).
*/
private static void parseCSVString() {
String csvData = "Apple,Banana,Cherry,Date";
Scanner sc = new Scanner(csvData);

// Set delimiter to comma
sc.useDelimiter(",");

while (sc.hasNext()) {
System.out.println("Token: " + sc.next());
}

sc.close();
}
/**
* Pattern 4: Validating input loop.
* Keeps asking until user enters a valid integer.
*/
private static void validateInputExample() {
Scanner console = new Scanner(System.in);
System.out.print("Enter an integer: ");
// Check if the next token is an integer BEFORE reading it
while (!console.hasNextInt()) {
String badInput = console.next(); // Consume the bad input
System.out.println("That's not a number! You typed: " + badInput);
System.out.print("Try again. Enter an integer: ");
}
int number = console.nextInt();
System.out.println("Success! You entered: " + number);
// Note: We usually do NOT close System.in scanners
}
// Helper method to create a dummy file
private static void createDummyFile(String filename) {
try (FileWriter writer = new FileWriter(filename)) {
writer.write("Player1 Score: 100\n");
writer.write("Player2 Score: 250\n");
writer.write("Player3 Score: 50");
} catch (IOException e) {
System.err.println("Setup failed: " + e.getMessage());
}
}
}


Analyze the following code snippet. If the input is '42' followed by a newline and then 'Java', what will be the value of the variable 'text'?

Scanner sc = new Scanner(System.in);int num = sc.nextInt();String text = sc.nextLine();

The answer: An empty string ""

nextInt() reads the number but leaves the newline character in the buffer; nextLine() immediately reads that remaining newline as an empty line.

The observation accurately describes a common behavior when mixing nextInt() (or next(), nextDouble(), etc.) with nextLine() in Java's Scanner class.
Explanation:
  • nextInt() and similar methods:
    Methods like nextInt(), next(), nextDouble() are designed to read specific data types (integers, tokens, doubles) and stop before consuming the newline character (\n) that is typically entered after the input by the user pressing the Enter key. This newline character remains in the input buffer.
  • nextLine():
    The nextLine() method, in contrast, reads the entire line of input, including any whitespace characters, until it encounters and consumes a newline character.
The Problem:
When you call nextInt() and then immediately call nextLine(), the nextLine() method finds the leftover newline character in the buffer from the previous nextInt() call. It interprets this leftover newline as the entire line of input and returns an empty string, effectively "skipping" the expected user input for that nextLine() call.
Solution:
To prevent this, you need to explicitly consume the leftover newline character after calling nextInt() (or other nextX() methods) and before calling nextLine(). This is typically done by adding an extra, empty nextLine() call:

import java.util.Scanner;

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

System.out.print("Enter an integer: ");
int number = scanner.nextInt();

// Consume the leftover newline character
scanner.nextLine();

System.out.print("Enter a string: ");
String text = scanner.nextLine();

System.out.println("You entered: " + number + " and " + text);

scanner.close();
}
}
In this example, scanner.nextLine(); after nextInt() reads and discards the newline character, ensuring that the subsequent scanner.nextLine(); correctly waits for and reads the user's string input.
← Back to Learning Journey