Console Input

Reading data typed by a user at the terminal is Java's most basic form of interactivity, handled almost universally through the Scanner class.

Most beginner and many production command-line Java programs need to read input from the console. The standard tool for this is java.util.Scanner wrapped around System.in, which offers convenient methods for reading tokens, whole lines, and typed values like integers and doubles. Getting comfortable with Scanner's quirks — especially the notorious newline-after-nextInt() issue — is an early rite of passage in Java.

What Is Scanner

Scanner is a class in java.util that parses text from an input source — most commonly System.in, the standard input stream connected to the console/terminal. It breaks input into tokens (by default, separated by whitespace) and offers typed methods to read those tokens as different Java types.

import java.util.Scanner;

Scanner scanner = new Scanner(System.in);

Token-Based Input

By default, Scanner treats runs of whitespace (spaces, tabs, newlines) as separators between tokens. next() reads and returns the next whitespace-delimited token as a String.

Scanner scanner = new Scanner(System.in);
System.out.print("Enter your first name: ");
String firstName = scanner.next();  // reads up to the next whitespace

Line-Based Input

nextLine() reads an entire line of input — everything up to (and consuming, but not including) the next newline character — regardless of internal whitespace. This is what you want for reading a full sentence, address, or any input that might contain spaces.

Scanner scanner = new Scanner(System.in);
System.out.print("Enter your full name: ");
String fullName = scanner.nextLine();   // e.g. "Ada Lovelace"

Numeric Input

Scanner provides typed reading methods for every primitive numeric type: nextInt(), nextLong(), nextDouble(), nextFloat(), nextBoolean(), and more. Each reads the next token and parses it as that type.

Scanner scanner = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = scanner.nextInt();
System.out.print("Enter your GPA: ");
double gpa = scanner.nextDouble();

The Classic nextInt()/nextLine() Newline Issue

nextInt() (and the other typed next-methods) reads only the numeric token itself — it leaves the trailing newline character in the input buffer, unconsumed. If you follow nextInt() with nextLine(), that nextLine() immediately reads the leftover empty remainder of the current line (up to that newline) instead of waiting for the user's next real line of input, appearing to 'skip' the intended prompt.

The fix is to consume the leftover newline explicitly, typically with an extra scanner.nextLine() call right after the numeric read, or by switching to reading everything with nextLine() and parsing values manually.

Scanner scanner = new Scanner(System.in);
System.out.print("Enter age: ");
int age = scanner.nextInt();       // consumes "25" but leaves the newline
System.out.print("Enter name: ");
String name = scanner.nextLine();  // BUG: immediately returns "", the leftover newline
int age = scanner.nextInt();
scanner.nextLine();               // consume the leftover newline
String name = scanner.nextLine(); // now reads the actual next line correctly

Parsing Input Manually

A common, robust alternative pattern is to always read with nextLine() and parse the resulting String yourself with methods like Integer.parseInt() or Double.parseDouble(). This sidesteps the mixed next()/nextLine() pitfall entirely, at the cost of an extra parsing step.

Scanner scanner = new Scanner(System.in);
System.out.print("Enter age: ");
int age = Integer.parseInt(scanner.nextLine().trim());

Handling Invalid Input

If the user types text that doesn't match the expected type (e.g. letters when nextInt() expects digits), Scanner throws an InputMismatchException — and critically, it does NOT consume the bad token, so a naive retry loop can spin forever re-reading the same invalid token. hasNextInt() (and friends) let you check before consuming.

Scanner scanner = new Scanner(System.in);
int age;
while (true) {
    System.out.print("Enter age: ");
    if (scanner.hasNextInt()) {
        age = scanner.nextInt();
        break;
    } else {
        System.out.println("Invalid number, try again.");
        scanner.next();   // discard the bad token so the loop can progress
    }
}

Closing Scanner and System.in

Scanner implements AutoCloseable, and closing it also closes the underlying stream. Closing a Scanner wrapped around System.in closes System.in itself — after that, no further console input can be read anywhere in the program (even a new Scanner over System.in will fail), because the underlying stream, not just this Scanner instance, has been closed.

For a short-lived console program, it's common and acceptable to simply never explicitly close a System.in-backed Scanner and let the JVM reclaim resources on exit — unlike a file-backed Scanner, which absolutely should be closed (ideally via try-with-resources) to release the file handle.

Scanner scanner = new Scanner(System.in);
// ... use scanner throughout the program's interactive portion ...
scanner.close(); // do this once, typically right before the program exits

Performance Considerations

Scanner is convenient but relatively slow compared to lower-level input mechanisms like BufferedReader, because of its regex-based tokenizing machinery. For interactive console programs reading a handful of values, this is irrelevant. For programs that need to read very large volumes of input quickly (e.g. competitive programming reading thousands of numbers), a BufferedReader with manual splitting/parsing is typically faster.

import java.io.BufferedReader;
import java.io.InputStreamReader;

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line = reader.readLine();
int n = Integer.parseInt(line.trim());

Practical Complete Example

import java.util.Scanner;

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

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

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

        System.out.print("Enter your GPA: ");
        double gpa = scanner.nextDouble();

        System.out.printf("%s is %d years old with a GPA of %.2f%n", name, age, gpa);

        scanner.close();
    }
}

Quick Reference

next()          - reads next whitespace-delimited token as String
nextLine()      - reads the rest of the current line as String
nextInt()       - reads next token, parses as int
nextDouble()    - reads next token, parses as double
nextBoolean()   - reads next token, parses as boolean
hasNext...()    - checks availability/type without consuming (mostly)
InputMismatchException - thrown when the token doesn't match the requested type
nextInt()/nextLine() mixing - classic newline pitfall; add an extra nextLine() to consume it

Key Takeaways

Scanner wraps an input source (typically System.in) and provides typed reading methods.

next() reads a whitespace-delimited token; nextLine() reads a full line.

Mixing nextInt()/nextDouble() with nextLine() leaves a leftover newline that causes the classic 'skipped input' bug — consume it explicitly.

Invalid input throws InputMismatchException without consuming the bad token, so guard with hasNextX() checks in robust programs.

Closing a Scanner over System.in closes System.in itself for the rest of the program.

For very large or performance-sensitive input, BufferedReader with manual parsing is typically faster than Scanner.

int age = scanner.nextInt(); String name = scanner.nextLine(); // gets "" int age = scanner.nextInt(); scanner.nextLine(); // consume leftover newline String name = scanner.nextLine();

nextInt() leaves the trailing newline in the buffer; the very next nextLine() call reads that leftover empty remainder instead of waiting for real input.

while (true) { if (!scanner.hasNextInt()) { System.out.println("invalid"); // loop again without consuming the bad token } } while (true) { if (!scanner.hasNextInt()) { System.out.println("invalid"); scanner.next(); // discard the bad token continue; } break; } hasNextInt() returning false does not consume the offending token. Without discarding it, the loop re-reads the same bad token forever.

Scanner s1 = new Scanner(System.in); s1.close(); Scanner s2 = new Scanner(System.in); // read more input later

Scanner s1 = new Scanner(System.in); // use s1 for the whole program's console input, close once at the very end

Closing a Scanner over System.in closes the shared underlying stream, not just that Scanner object — a fresh Scanner over System.in afterward cannot read any more input.

Why does calling nextLine() immediately after nextInt() often appear to 'skip' a prompt?

nextInt() only consumes the numeric token itself, leaving the newline character that ended that line still in the input buffer. The very next nextLine() call reads up to that leftover newline, returning an empty string instead of waiting for a new line of input.

What is the difference between next() and nextLine()?

next() reads a single whitespace-delimited token. nextLine() reads everything up to the next newline, including internal spaces, and consumes the newline.

What exception does Scanner throw when the input doesn't match the requested type, and what happens to the offending input token?

It throws InputMismatchException. The token that failed to parse is NOT consumed, so it remains available to be re-read (or discarded) on the next call.

What happens if you call scanner.close() on a Scanner wrapping System.in, and then try to read more console input elsewhere in the program?

It fails, because closing that Scanner also closes the shared System.in stream itself — not just this Scanner instance — so no further reads from System.in are possible, even through a new Scanner.

Why might a program prefer BufferedReader over Scanner for performance-critical input reading?

Scanner's tokenizing relies on regular-expression-based pattern matching internally, which carries more per-call overhead than BufferedReader's simpler line-based reading, making BufferedReader faster for reading very large volumes of input.

How can you check whether the next token is a valid integer before consuming it?

Use scanner.hasNextInt(), which returns true or false based on whether the next token can be parsed as an int, without actually consuming it.

Why is 'always read with nextLine() and parse manually' considered a robust pattern?

It avoids ever mixing next-family typed reads (nextInt, nextDouble, etc.) with nextLine() in the same input stream, sidestepping the classic leftover-newline bug entirely, at the modest cost of an explicit parsing step.

Write a program that prompts for a person's name (which may contain spaces) and their age, and prints them back correctly, avoiding the newline pitfall.

import java.util.Scanner; public class Info { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Name: "); String name = scanner.nextLine(); System.out.print("Age: "); int age = Integer.parseInt(scanner.nextLine().trim()); System.out.println(name + " is " + age); scanner.close(); } }

Reading both values with nextLine() and parsing the age manually avoids mixing nextInt() with nextLine(), so no leftover newline problem occurs.

If the user types 5 then presses Enter, what does this print, and why?

It prints "[]" — an empty bracket pair. nextInt() consumes only "5", leaving the newline after it; the following nextLine() reads that leftover empty remainder instead of the intended comment text.

Write a loop that keeps prompting the user until they enter a valid positive integer, using hasNextInt() to guard against invalid input.

Scanner scanner = new Scanner(System.in); int value; while (true) { System.out.print("Enter a positive integer: "); if (scanner.hasNextInt()) { value = scanner.nextInt(); if (value > 0) break; System.out.println("Must be positive."); } else { System.out.println("Not a number."); scanner.next(); // discard invalid token } } System.out.println("Got: " + value);

The loop checks hasNextInt() before consuming, discards non-numeric tokens with scanner.next() so it doesn't spin on the same bad input, and additionally validates that the parsed value is positive before exiting.

Scanner sc = new Scanner(System.in);
System.out.print("Enter a number: ");
int n = sc.nextInt();
System.out.print("Enter a comment: ");
String comment = sc.nextLine();
System.out.println("[" + comment + "]");