Skip to content
Home Java Java Scanner — The Silent Skip That Lost Payment Data

Java Scanner — The Silent Skip That Lost Payment Data

Where developers are forged. · Structured learning · Free forever.
📍 Part of: Java I/O → Topic 7 of 8
After nextInt() in batch, nextLine() returns empty strings - silent data loss.
🧑‍💻 Beginner-friendly — no prior Java experience needed
In this tutorial, you'll learn
After nextInt() in batch, nextLine() returns empty strings - silent data loss.
  • Scanner is a wrapper around any readable source — swap System.in for a File object and the entire API works identically, which means one skill covers two common use cases.
  • nextInt(), nextDouble() and friends leave the newline character in the buffer — always consume it with an extra nextLine() before reading your next string to avoid the empty-string bug.
  • Always use hasNextInt() (or hasNextDouble()) to validate input before parsing it — nextInt() on bad input throws InputMismatchException and crashes; hasNextInt() peeks safely without consuming the token.
✦ Plain-English analogy ✦ Real code with output ✦ Interview questions
Quick Answer
  • Scanner wraps System.in or File to read text input, converting tokens to Java types.
  • Key methods: nextLine(), nextInt(), nextDouble() — each parses a specific type.
  • hasNextInt() and similar let you validate before reading — prevents InputMismatchException crashes.
  • Performance: Scanner is slower than BufferedReader for large files due to regex parsing overhead.
  • Production trap: nextLine() after nextInt() silently reads leftover newline — always add an extra nextLine().
  • Biggest mistake: Multiple Scanner objects on System.in — closing one closes the stream for all.
🚨 START HERE

Quick Debug Cheat Sheet for Scanner Input

When Scanner misbehaves, use these commands and checks to diagnose and fix fast.
🟡

nextLine() skipping input

Immediate ActionCheck if a numeric reading method was called just before. If yes, add an extra nextLine() to consume newline.
Commands
Add: inputReader.nextLine(); // discard leftover newline
If you can change design: use Integer.parseInt(inputReader.nextLine()) for all number reading.
Fix NowInsert an extra nextLine() call right after nextInt().
🟡

InputMismatchException crash

Immediate ActionWrap the read in a try-catch or pre-check with hasNextXxx().
Commands
if (scanner.hasNextInt()) { int num = scanner.nextInt(); } else { String bad = scanner.next(); // consume }
Use scanner.next() to consume invalid token and avoid infinite loop.
Fix NowAdd hasNextInt() guard before nextInt().
🟡

Scanner won't close or resource warning

Immediate ActionCheck if you created multiple Scanner objects. Use try-with-resources for file Scanners.
Commands
For file: try (Scanner fileScanner = new Scanner(new File(...))) { ... }
For System.in: create one global Scanner, close in finally after all input done.
Fix NowWrap file Scanner in try-with-resources. For System.in, close only once.
🟡

Infinite loop in validation

Immediate ActionEnsure you consume the invalid token in the else branch.
Commands
scanner.next(); // MUST consume bad input
Check that loop condition will eventually become false when valid input arrives.
Fix NowAdd scanner.next() in the else block to remove the bad token.
Production Incident

The Silent Skip: How nextLine() After nextInt() Caused Data Loss in a Payment Pipeline

A payment batch processing system silently skipped customer names because nextLine() after nextInt() consumed the leftover newline — leading to unlabeled transactions and a critical audit failure.
SymptomIn a batch file processing job, after reading an integer (transaction amount), the subsequent nextLine() to read the customer name returned an empty string, causing all names to be blank. Audit reports flagged missing data.
AssumptionDevelopers assumed nextLine() would correctly read the next line of input, not realizing that nextInt(), nextDouble() etc. leave the newline character (\n) in the input buffer.
Root causenextInt() reads only the numeric token and stops at whitespace, leaving the newline character (Enter key) in the buffer. The very next call to nextLine() reads that leftover newline and returns immediately with an empty string — it reads an empty line, not the actual next line.
FixAdd an extra scanner.nextLine() call immediately after nextInt() (or nextDouble()) to consume the leftover newline before reading the actual string line.
Key Lesson
The newline left by nextInt(), nextDouble(), next(), etc. is a silent state — invisible to most code reviews.Always insert a dummy nextLine() after any nextXxx() call that reads a token, if a nextLine() follows.Better yet: read everything as strings with nextLine() and parse numbers separately using Integer.parseInt() — this eliminates the newline problem entirely and makes parsing errors easier to handle.
Production Debug Guide

Quick symptom-to-action reference for common Scanner problems in production or development.

nextLine() returns empty string after nextInt()Insert an extra scanner.nextLine() after nextInt() to consume the leftover newline. Alternatively, parse numbers from nextLine() via Integer.parseInt().
InputMismatchException thrown when user types non-numeric dataUse hasNextInt() / hasNextDouble() before reading to validate. If invalid, call scanner.next() to consume the bad token and prompt again.
Scanner loop runs forever without asking for inputCheck if you are consuming the bad token inside the else branch of a validation loop. Always call scanner.next() if input is invalid to remove it from the buffer.
NoSuchElementException when using Scanner after closing another Scanner on System.inEnsure only one Scanner object is created for System.in. Pass it around as a parameter rather than creating multiple instances. Close it exactly once at program end.
File Scanner reads empty lines or skips contentVerify file encoding matches the expectation (default charset). Use hasNextLine() carefully — if file ends with a blank line, it may still return true. Trim lines or check length.

Every useful program in the real world needs to talk to a human. A login screen needs a username. A calculator needs two numbers. A quiz app needs an answer. Without the ability to read what a user types, your Java program is essentially a locked room — it can think, but it can't listen. That's where the Scanner class steps in, and it's one of the very first things every Java developer learns for exactly that reason.

Before Scanner existed, reading input from a keyboard in Java was genuinely painful. You had to work with low-level streams, wrap them in readers, and handle checked exceptions just to read a single number. Scanner wraps all of that complexity in a clean, beginner-friendly API. You get methods like nextLine(), nextInt(), and nextDouble() that read exactly the type of data you want — no ceremony required.

By the end of this article you'll know how to set up a Scanner, read strings and numbers from the keyboard, read input from a file, close the Scanner correctly, and — critically — avoid the two nasty bugs that trip up almost every beginner. You'll also have three fully runnable programs you can copy, run, and tweak right now.

What Is Scanner and How Do You Set It Up?

Scanner lives in the java.util package, which means you need to import it before you can use it. Think of an import like telling your kitchen which cookbook to pull off the shelf — you're telling Java 'I need the Scanner recipe from the java.util cookbook'.

Once imported, you create a Scanner object. An object is just a working instance of a class — like printing a specific form from a template. You hand the Scanner constructor a source to read from. The most common source is System.in, which represents the keyboard. Literally: System.in means 'standard input', which is the stream of characters that flows in when a user types.

The Scanner then sits and waits. When your code calls a method like nextLine(), the program pauses, a cursor blinks in the terminal, the user types something and hits Enter, and Scanner captures everything typed before that Enter key.

One important habit to build immediately: always close your Scanner when you're done with it. A Scanner holds a connection to its source (keyboard or file). Leaving it open is like leaving a tap running — it wastes resources and can cause subtle bugs in larger programs.

GreetUser.java · JAVA
12345678910111213141516171819202122
import java.util.Scanner; // Step 1: import Scanner from the java.util package

public class GreetUser {

    public static void main(String[] args) {

        // Step 2: create a Scanner object connected to the keyboard (System.in)
        Scanner keyboardReader = new Scanner(System.in);

        // Step 3: prompt the user so they know what to type
        System.out.print("Enter your name: ");

        // Step 4: read the entire line the user types (including spaces)
        String userName = keyboardReader.nextLine();

        // Step 5: use the input — here we just greet the user
        System.out.println("Hello, " + userName + "! Welcome to TheCodeForge.");

        // Step 6: always close the Scanner when you're finished reading
        keyboardReader.close();
    }
}
▶ Output
Enter your name: Sarah
Hello, Sarah! Welcome to TheCodeForge.
🔥Why System.in?
System.in is Java's built-in handle to whatever is connected to standard input — usually the keyboard in a terminal. When you write new Scanner(System.in) you're saying 'watch the keyboard and give me what the user types'. Later you'll see you can swap System.in for a File object and Scanner will read a text file in exactly the same way.
📊 Production Insight
Forgetting to close a Scanner on System.in is often harmless in simple programs, but in long-running apps (e.g., a CLI tool reading multiple inputs), unclosed Scanners can leak file descriptors.
If you create a Scanner in a method and never close it, and the method is called repeatedly, you'll eventually see 'Too many open files' errors.
Rule: close every Scanner you open — for System.in, do it once at the very end of your program.
🎯 Key Takeaway
Import java.util.Scanner, then instantiate with new Scanner(System.in).
Prompt users before reading with System.out.print().
Always close the Scanner — for files use try-with-resources; for System.in close once at program end.

Reading Different Data Types — Strings, Integers and Decimals

Scanner doesn't just read raw text. It can parse that text directly into the Java data type you need — int, double, boolean, and more. Each data type has its own dedicated method, and choosing the right one saves you from having to convert strings manually.

nextLine() reads an entire line of text up to (but not including) the newline character created by pressing Enter. It returns a String.

next() reads a single 'token' — one word, stopping at whitespace. Useful for reading one word at a time.

nextInt() reads the next token and tries to parse it as a whole number (int). If the user types '42', you get the integer 42, ready for arithmetic.

nextDouble() does the same for decimal numbers. The user types '3.14' and you get a double you can multiply, divide, or compare.

The program below builds a simple age-and-height form. Notice how we mix data types in one conversation — that's exactly what real programs do.

UserProfileForm.java · JAVA
123456789101112131415161718192021222324252627282930313233343536
import java.util.Scanner;

public class UserProfileForm {

    public static void main(String[] args) {

        Scanner inputReader = new Scanner(System.in);

        // --- Read a String ---
        System.out.print("What is your full name? ");
        String fullName = inputReader.nextLine(); // reads the whole line, spaces included

        // --- Read an integer ---
        System.out.print("How old are you? ");
        int age = inputReader.nextInt(); // parses the typed text directly into an int

        // --- Read a double ---
        System.out.print("What is your height in metres? ");
        double heightInMetres = inputReader.nextDouble(); // parses into a decimal number

        // --- Display a summary ---
        System.out.println("\n--- Profile Summary ---");
        System.out.println("Name   : " + fullName);
        System.out.println("Age    : " + age + " years");
        System.out.printf("Height : %.2f m%n", heightInMetres); // %.2f = 2 decimal places

        // Calculate something real with the input
        if (age >= 18) {
            System.out.println("Status : Adult");
        } else {
            System.out.println("Status : Minor");
        }

        inputReader.close();
    }
}
▶ Output
What is your full name? Maria Gonzalez
How old are you? 24
What is your height in metres? 1.68

--- Profile Summary ---
Name : Maria Gonzalez
Age : 24 years
Height : 1.68 m
Status : Adult
⚠ Watch Out: The nextInt() + nextLine() Trap
When you call nextInt() and then nextLine() right after it, nextLine() reads the leftover newline character from when the user pressed Enter after typing the number — so it returns an empty string instead of the next line of text. The fix is to add an extra inputReader.nextLine() call immediately after nextInt() to consume that leftover newline before you read your actual string. This is covered in detail in the Common Mistakes section below.
📊 Production Insight
The nextInt()+nextLine() bug is the most common Scanner mistake in production.
It causes silent data corruption — the program continues but with empty string values for expected input.
Rule: always flush the newline after every nextInt(), nextDouble(), or next() call if you plan to use nextLine() afterwards.
🎯 Key Takeaway
nextLine() reads full lines with spaces; next() reads one word; nextInt() reads an integer.
nextInt(), nextDouble(), etc. leave the newline in the buffer — always follow with nextLine().
Use the hasNextXxx() family to validate input type before reading to avoid crashes.

Reading Input From a File — Same Tool, Different Source

Here's something that surprises many beginners: Scanner isn't just for keyboards. Because it accepts any source that Java can read from, you can point it at a text file and it reads line by line (or token by token) in exactly the same way. This is genuinely powerful — learn Scanner once, use it two ways.

To read from a file, you create a File object pointing at the file path, then pass that File object to the Scanner constructor instead of System.in. The rest of the API — nextLine(), nextInt(), hasNextLine() — works identically.

hasNextLine() is your best friend when reading files. It returns true as long as there are more lines to read, which makes it a perfect condition for a while loop. Without it you'd have to know in advance how many lines the file has.

Note that opening a file can fail (file not found, permission denied), so Java forces you to handle a FileNotFoundException. We use a try-with-resources block below, which is the modern, correct approach — it automatically closes the Scanner when the block ends, even if an exception occurs.

FileLineReader.java · JAVA
123456789101112131415161718192021222324252627282930313233343536
import java.util.Scanner;
import java.io.File;             // needed to represent the file on disk
import java.io.FileNotFoundException; // thrown if the file doesn't exist

public class FileLineReader {

    public static void main(String[] args) {

        // Imagine scores.txt contains:
        // Alice 95
        // Bob 87
        // Carol 92

        File scoresFile = new File("scores.txt"); // point to the file

        // try-with-resources: Scanner is automatically closed when the block ends
        try (Scanner fileScanner = new Scanner(scoresFile)) {

            int lineNumber = 1;

            // hasNextLine() returns true if there is another line to read
            while (fileScanner.hasNextLine()) {

                String currentLine = fileScanner.nextLine(); // read one full line
                System.out.println("Line " + lineNumber + ": " + currentLine);
                lineNumber++;
            }

            System.out.println("\nFinished reading " + (lineNumber - 1) + " lines.");

        } catch (FileNotFoundException exception) {
            // This runs if scores.txt doesn't exist in the project directory
            System.out.println("Error: File not found — " + exception.getMessage());
        }
    }
}
▶ Output
Line 1: Alice 95
Line 2: Bob 87
Line 3: Carol 92

Finished reading 3 lines.
💡Pro Tip: Use try-with-resources Every Time
The try-with-resources syntax (try (Scanner s = new Scanner(...)) { ... }) guarantees the Scanner is closed the moment the block ends — whether it exits normally or throws an exception. This is cleaner and safer than manually calling close() in a finally block, and it's the pattern you'll see in all modern Java codebases.
📊 Production Insight
File Scanners left open can prevent file deletion on Windows and cause resource leaks across the JVM.
If you parse large files (~100MB+), Scanner's regex-based tokenization becomes a bottleneck — consider BufferedReader for raw line reads.
Rule: always use try-with-resources for file Scanners; if you need performance, switch to BufferedReader and parse numbers manually.
🎯 Key Takeaway
Swap System.in for a File object to read files — same API.
Use hasNextLine() in a while loop to read until end of file.
Let try-with-resources handle closure automatically; never manually close a file Scanner in production.

Validating Input in a Loop — Building a Bulletproof Input Reader

Real programs can't trust users to type perfectly. Someone will type 'abc' when you asked for a number. If nextInt() gets a non-numeric token it throws an InputMismatchException and crashes your program. That's a terrible user experience.

The professional solution is to validate input inside a loop. Scanner's hasNextInt() method (and its siblings hasNextDouble(), hasNextLong()) lets you check whether the next token is actually parseable as that type — before you try to parse it. Think of it as asking 'is the next thing in the queue actually a number?' before reaching in to grab it.

The loop below keeps asking until the user provides a valid positive integer. Notice two things: we call next() to consume the bad token when validation fails (otherwise Scanner is stuck on the same bad input forever), and we give the user a clear error message so they understand what went wrong.

SafeAgeInput.java · JAVA
12345678910111213141516171819202122232425262728293031323334
import java.util.Scanner;

public class SafeAgeInput {

    public static void main(String[] args) {

        Scanner console = new Scanner(System.in);
        int userAge = -1; // sentinel value: -1 means 'not yet set'

        // Keep looping until we have a valid age
        while (userAge < 0 || userAge > 130) {

            System.out.print("Please enter your age (0–130): ");

            if (console.hasNextInt()) { // check BEFORE parsing — safe!

                userAge = console.nextInt();

                if (userAge < 0 || userAge > 130) {
                    // The input was an integer but outside our acceptable range
                    System.out.println("That age isn't realistic. Try again.");
                }

            } else {
                // The input wasn't an integer at all (e.g., the user typed 'hello')
                String badInput = console.next(); // MUST consume the bad token or we loop forever
                System.out.println("'" + badInput + "' is not a number. Please type digits only.");
            }
        }

        System.out.println("Great — you are " + userAge + " years old.");
        console.close();
    }
}
▶ Output
Please enter your age (0–130): hello
'hello' is not a number. Please type digits only.
Please enter your age (0–130): -5
That age isn't realistic. Try again.
Please enter your age (0–130): 27
Great — you are 27 years old.
🔥Interview Gold: hasNextInt() vs nextInt()
Interviewers love asking why you'd use hasNextInt() before nextInt(). The answer: nextInt() throws InputMismatchException if the token isn't an integer, which crashes the program. hasNextInt() is a non-destructive peek — it checks without consuming the token, so you can branch safely. This shows you understand defensive programming, not just happy-path coding.
📊 Production Insight
Input validation loops are critical for any interactive application — CLI tools, chatbots, form prompts.
Without consuming the bad token via next(), your loop becomes an infinite error printer — a classic bug that crashes nothing but infuriates users.
Rule: always call next() in the else branch of a hasNextXxx() check to remove the invalid token from the buffer.
🎯 Key Takeaway
Use hasNextInt() / hasNextDouble() to safely check before parsing.
Always consume the invalid token with next() in the else branch.
Combine range validation after parsing to catch semantically invalid but syntactically correct input.

Custom Delimiters — Reading Comma-Separated Data Like a Pro

By default, Scanner splits input on whitespace (spaces, tabs, newlines). But you can change this behavior using the useDelimiter() method. This is incredibly useful when you need to parse structured data like CSV lines, pipe-delimited logs, or any custom-separated input.

useDelimiter() takes a regular expression (or a Pattern) that defines the new delimiter. Once set, all nextXxx() methods will split tokens based on that pattern instead of whitespace.

A common use case: reading a line from a CSV file where values are separated by commas. You can set the delimiter to "," or a more robust pattern like ",|" to handle multiple delimiters.

Be careful: after setting a custom delimiter, nextLine() behavior changes — it reads tokens up to the newline, but the delimiter may include newline characters. Usually, for CSV parsing, you read each line with nextLine() first, then create a new Scanner for that line with a comma delimiter. That's the pattern shown below.

CsvParser.java · JAVA
1234567891011121314151617181920212223
import java.util.Scanner;

public class CsvParser {

    public static void main(String[] args) {
        String csvLine = "Alice,30,Engineer";

        // Create a Scanner for the single line with comma delimiter
        Scanner lineScanner = new Scanner(csvLine);
        lineScanner.useDelimiter(",");

        // Read tokens in order
        String name = lineScanner.next();      // Alice
        int age = lineScanner.nextInt();        // 30
        String job = lineScanner.next();        // Engineer

        System.out.println("Name: " + name);
        System.out.println("Age:  " + age);
        System.out.println("Job:  " + job);

        lineScanner.close();
    }
}
▶ Output
Name: Alice
Age: 30
Job: Engineer
💡Real-World CSV Pitfall
CSV files can have quoted fields with commas inside. Scanner's simple delimiter won't handle that. For production CSV parsing, use a dedicated library like Apache Commons CSV or OpenCSV. Scanner is fine for simple, unquoted CSV data.
📊 Production Insight
Changing the delimiter globally on a Scanner that reads from System.in will break normal user input — a common mistake when reusing the same Scanner for both structured and free-text input.
Always create a separate Scanner for the delimited data using the string or file source.
Rule: never modify the delimiter on a Scanner tied to System.in; instead create a new Scanner for the specific token stream.
🎯 Key Takeaway
useDelimiter() lets you parse custom formats like CSV.
For files, read lines with nextLine() then create a temporary Scanner per line with useDelimiter.
Never change delimiter on System.in Scanner — that causes unexpected input behavior.

Scanner vs BufferedReader — When to Upgrade

Scanner is great for learning and small programs, but it has performance limitations. For reading large files (hundreds of MB), Scanner's regex-based tokenization becomes slow. That's when you reach for BufferedReader.

BufferedReader reads text from a character stream efficiently by buffering chunks of data. It only returns raw strings — you have to parse numbers or split lines yourself. But that trade-off gives you speed.

Use Scanner when
  • You need to parse different data types from the same stream.
  • Input size is small (a few MB or user keyboard input).
  • You want simple methods like nextInt() without manual parsing.
Use BufferedReader when
  • Performance matters (big files, high-frequency reads).
  • You only need to read lines as strings.
  • You want more control over encoding and buffer size.

If you're in a production system reading transaction logs, choose BufferedReader. If you're writing a quick CLI utility, Scanner is fine.

BufferedReaderExample.java · JAVA
12345678910111213141516171819
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderExample {

    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("largefile.txt"))) {
            String line;
            while ((line = br.readLine()) != null) {
                // Manually parse if needed
                String[] parts = line.split(",");
                // process parts
            }
        } catch (IOException e) {
            System.err.println("Error reading file: " + e.getMessage());
        }
    }
}
🔥Performance Comparison
For a 100 MB CSV file, BufferedReader can be 5-10x faster than Scanner due to Scanner's internal regex scanning and smaller default buffer. If you need to parse numbers, use Integer.parseInt() on the split tokens — still faster than Scanner.nextDouble().
📊 Production Insight
In a high-frequency trading feed parsing pipeline, using Scanner for each message caused 30% CPU overhead due to regex compilation and tokenization.
Switching to BufferedReader with manual split and parse reduced latency by 80%.
Rule: if you're processing more than a few megabytes of input per request, or if throughput is critical, skip Scanner and use BufferedReader.
🎯 Key Takeaway
Scanner is slower than BufferedReader due to regex overhead.
Use Scanner for small input and ease of parsing; use BufferedReader for large files or performance-critical paths.
Always measure before optimizing — don't prematurely replace Scanner if it meets your needs.
🗂 Scanner Method Reference
All common Scanner methods with their return types and behavior
Scanner MethodWhat It ReadsReturnsStops At
nextLine()Everything up to Enter keyString (can contain spaces)Newline character \n
next()One word / tokenString (no spaces)Any whitespace
nextInt()Next token as a whole numberintWhitespace (leaves \n behind)
nextDouble()Next token as a decimaldoubleWhitespace (leaves \n behind)
nextBoolean()Next token as true/falsebooleanWhitespace
hasNextLine()Does another line exist?boolean (true/false)Does not consume input
hasNextInt()Is the next token an int?boolean (true/false)Does not consume input

🎯 Key Takeaways

  • Scanner is a wrapper around any readable source — swap System.in for a File object and the entire API works identically, which means one skill covers two common use cases.
  • nextInt(), nextDouble() and friends leave the newline character in the buffer — always consume it with an extra nextLine() before reading your next string to avoid the empty-string bug.
  • Always use hasNextInt() (or hasNextDouble()) to validate input before parsing it — nextInt() on bad input throws InputMismatchException and crashes; hasNextInt() peeks safely without consuming the token.
  • Create exactly one Scanner per input source and close it exactly once — multiple Scanners on System.in will cause NoSuchElementException; use try-with-resources for file Scanners to guarantee cleanup even if an exception occurs.
  • For large files or performance-critical reads, switch to BufferedReader — Scanner's regex-based tokenization causes significant overhead.

⚠ Common Mistakes to Avoid

    Calling nextLine() right after nextInt() returns an empty string
    Symptom

    After reading an integer with nextInt(), the next nextLine() returns an empty string instead of the user's input. The program skips the prompt and moves on without waiting.

    Fix

    Add an extra scanner.nextLine() call immediately after nextInt() (or nextDouble()) to consume the leftover newline. Or read the number with Integer.parseInt(scanner.nextLine()) to avoid the newline issue entirely.

    Forgetting to consume the bad token inside a hasNextInt() validation loop
    Symptom

    The loop runs forever printing the same error message because Scanner is stuck on the same invalid token and keeps returning false for hasNextInt().

    Fix

    Inside the else branch, call scanner.next() to discard the invalid token and advance the Scanner position. Optionally assign it to a variable for logging.

    Creating multiple Scanner objects pointing to System.in
    Symptom

    Closing one Scanner closes System.in for all other Scanners. Subsequent read attempts throw NoSuchElementException because the underlying stream is closed.

    Fix

    Create exactly one Scanner for System.in, pass it as a method parameter or store it in a static variable. Close it exactly once when the entire program has finished reading input.

    Using Scanner with useDelimiter() on System.in and then expecting normal line input
    Symptom

    After calling scanner.useDelimiter(","), nextLine() behaves unexpectedly because the delimiter definition affects how tokens are split. Reading a full line becomes inconsistent.

    Fix

    Never change the delimiter on a Scanner connected to System.in. Instead, create a separate Scanner for the delimited string or file.

Interview Questions on This Topic

  • QWhat is the difference between next() and nextLine() in Java's Scanner class, and when would you choose one over the other?JuniorReveal
    next() reads a single token delimited by whitespace, returning a String without spaces. nextLine() reads everything until the end of the current line, including spaces. Use next() when you need a single word (like a command), and nextLine() when you need a full line of text (like a name or address). Be cautious: after next() or nextInt(), the newline remains in the buffer, so a subsequent nextLine() will consume it and return an empty string. Always flush with an extra nextLine() after a token-based read if you plan to use nextLine() afterwards.
  • QWhy does calling nextLine() immediately after nextInt() sometimes return an empty string, and how do you fix it?JuniorReveal
    nextInt() reads the integer but leaves the newline character (from pressing Enter) in the input buffer. The immediate nextLine() reads that leftover newline and returns an empty string. Fix by inserting an extra scanner.nextLine() call after nextInt() to consume the leftover newline before reading your actual string. Alternatively, read the entire line as a String and parse the integer from it: int age = Integer.parseInt(scanner.nextLine());
  • QIf you need to read from both the keyboard and a file in the same program, how would you structure your Scanner usage to avoid resource leaks?Mid-levelReveal
    Create two separate Scanner instances: one for System.in and one for the file. For the file Scanner, use try-with-resources to guarantee auto-closing even if an exception occurs. For System.in, create a single Scanner at the start of the program, pass it to methods that need it, and close it manually at the end of the program after all input is consumed. Never close System.in early (e.g., inside a method) because that will close the underlying stream and break the keyboard Scanner for the rest of the program.
  • QHow does hasNextInt() differ from nextInt() in terms of behavior and safety?Mid-levelReveal
    hasNextInt() is a non-destructive check that returns true if the next token can be parsed as an int, without consuming the token. nextInt() attempts to parse and consume the token, throwing InputMismatchException if it fails. Defensive programming uses hasNextInt() first to avoid exceptions, then reads with nextInt(). This pattern is preferred in interactive programs to gracefully handle invalid input. Additionally, hasNextInt() does not block for keyboard input as long as there's a token available; it checks the buffer without waiting.
  • QCan you use Scanner to read from a URL or network stream? How?SeniorReveal
    Yes, Scanner accepts any Readable or InputStream, so you can read from a URL by wrapping its InputStream: Scanner scanner = new Scanner(url.openStream()). Then use the same methods (nextLine, nextInt, etc.) to parse the content. However, network streams may block, so you should handle exceptions (IOException) and consider using a timeout if needed. This is useful for simple web scraping or reading API responses in small applications, but for production, consider more robust HTTP clients like HttpClient.

Frequently Asked Questions

Do I need to close the Scanner after using it?

Yes, you should always close a Scanner when you're finished with it. An unclosed Scanner holds an open connection to its source (keyboard or file), which wastes system resources. For file Scanners, use try-with-resources to close automatically. For System.in, call close() at the end of your program — but be aware that closing it also closes System.in itself, so only do it once.

What is the difference between Scanner and BufferedReader in Java?

Scanner is easier to use for beginners because it parses data types directly (nextInt(), nextDouble(), etc.) and works with multiple sources including keyboards and files. BufferedReader is faster and better for reading large files line by line, but it only returns Strings — you have to parse types manually. For most beginner and intermediate programs, Scanner is the right choice. Switch to BufferedReader when performance with large files becomes a concern.

Why does my Scanner program skip a line of input without waiting for me to type?

This is almost certainly the nextInt()-then-nextLine() bug. When you read a number with nextInt(), it consumes the digits but leaves the Enter key's newline character in the input buffer. The immediately following nextLine() reads that leftover newline and returns instantly with an empty string. Fix it by adding an extra scanner.nextLine() call right after nextInt() to discard the leftover newline before you read your actual string.

Can Scanner read from sources other than keyboard and file?

Yes, Scanner can read from any object that implements Readable or provides an InputStream. You can pass a String directly to the constructor, or read from network sources by wrapping an InputStream from a URL or socket. This makes Scanner surprisingly versatile for simple parsing tasks.

What is the default delimiter for Scanner and how do I change it?

The default delimiter is any whitespace pattern defined by the regex \p{javaWhitespace}+. You can change it using scanner.useDelimiter(String pattern) or useDelimiter(Pattern pattern). For example, to parse comma-separated values, call scanner.useDelimiter(","). Be careful: changing the delimiter affects all subsequent read methods, including nextLine() behavior.

🔥
Naren Founder & Author

Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.

← PreviousWorking with JSON in JavaNext →Java PrintWriter and PrintStream
Forged with 🔥 at TheCodeForge.io — Where Developers Are Forged