Skip to content
Java io 6 min read

Scanner

Scanner is Java’s go-to tool for reading input from almost anywhere — the keyboard, a file, a string, or any InputStream. It tokenises the input and gives you a rich set of typed methods (nextInt(), nextDouble(), nextLine(), …) so you can pull data in exactly the shape you need without writing your own parsing code.

What Is Scanner?

Scanner lives in java.util (not java.io) and implements Iterator<String>. Under the hood it wraps any Readable or InputStream source, splits the stream into tokens using a configurable delimiter (whitespace by default), and lets you read each token as a specific Java type.

import java.util.Scanner;

public class HelloScanner {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter your name: ");
        String name = sc.nextLine();
        System.out.println("Hello, " + name + "!");
        sc.close();
    }
}

Output (example run):

Enter your name: Alice
Hello, Alice!

Tip: Always call sc.close() when you are done, or use a try-with-resources block, to release the underlying stream.

Creating a Scanner

You can attach a Scanner to three common sources:

SourceConstructor
Standard input (keyboard)new Scanner(System.in)
A filenew Scanner(new File("data.txt"))
A stringnew Scanner("42 3.14 hello")
import java.io.File;
import java.util.Scanner;

// Reading from a file
try (Scanner fileScanner = new Scanner(new File("numbers.txt"))) {
    while (fileScanner.hasNextInt()) {
        System.out.println(fileScanner.nextInt());
    }
}

// Reading from a String
Scanner strScanner = new Scanner("Java 21 rocks");
System.out.println(strScanner.next());    // Java
System.out.println(strScanner.nextInt()); // 21
System.out.println(strScanner.next());    // rocks
strScanner.close();

Note: When you read from a File, the constructor throws a checked FileNotFoundException, so your method must declare it or you must catch it.

Reading Primitives and Strings

Scanner provides a dedicated next*() method for every primitive type plus String:

MethodReturnsReads until
next()Stringnext whitespace-delimited token
nextLine()Stringend of the current line
nextInt()intnext token parsed as int
nextLong()longnext token parsed as long
nextDouble()doublenext token parsed as double
nextFloat()floatnext token parsed as float
nextBoolean()booleantrue or false (case-insensitive)
import java.util.Scanner;

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

        System.out.print("Enter age: ");
        int age = sc.nextInt();

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

        // consume the leftover newline before nextLine()
        sc.nextLine();

        System.out.print("Enter city: ");
        String city = sc.nextLine();

        System.out.printf("Age=%d, GPA=%.2f, City=%s%n", age, gpa, city);
        sc.close();
    }
}

Output (example run):

Enter age: 22
Enter GPA: 3.75
Enter city: Toronto
Age=22, GPA=3.75, City=Toronto

The nextLine() Trap

This is the most common beginner mistake with Scanner. When you call nextInt() (or any other next*() method), Scanner reads only the token — it leaves the newline character (\n) sitting in the buffer. If you then call nextLine(), it immediately reads that leftover newline and returns an empty string.

The fix: add a dummy sc.nextLine() call after any next*() method before you call nextLine().

Scanner sc = new Scanner(System.in);

int id = sc.nextInt();
sc.nextLine(); // consume the leftover '\n'

String label = sc.nextLine(); // now reads the next real line
System.out.println(id + " -> " + label);
sc.close();

Warning: Forgetting the dummy nextLine() after nextInt() / nextDouble() is the single most frequent Scanner bug. Always remember to consume the newline.

hasNext() — Checking Before Reading

Every next*() method has a matching hasNext*() guard. Use them to avoid NoSuchElementException or InputMismatchException at runtime.

import java.util.Scanner;

public class SumIntegers {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int sum = 0;

        System.out.println("Enter integers (Ctrl+D / Ctrl+Z to stop):");
        while (sc.hasNextInt()) {
            sum += sc.nextInt();
        }

        System.out.println("Sum = " + sum);
        sc.close();
    }
}

Output (example run):

Enter integers (Ctrl+D / Ctrl+Z to stop):
10 20 30
Sum = 60

The full set of guard methods mirrors the read methods: hasNext(), hasNextLine(), hasNextInt(), hasNextDouble(), etc.

Custom Delimiters

By default Scanner splits on any whitespace. You can change this with useDelimiter(String pattern), which accepts a regular expression. This makes Scanner surprisingly powerful for parsing CSV or other delimited text.

import java.util.Scanner;

public class CsvParser {
    public static void main(String[] args) {
        String csv = "Alice,30,Engineer";
        Scanner sc = new Scanner(csv).useDelimiter(",");

        String name = sc.next();
        int age  = sc.nextInt();
        String job  = sc.next();

        System.out.printf("%s is %d years old and works as %s.%n", name, age, job);
        sc.close();
    }
}

Output:

Alice is 30 years old and works as Engineer.

Tip: For serious CSV work (quoting, embedded commas, escape sequences) prefer a dedicated library like Apache Commons CSV. Scanner with a custom delimiter works well for simple, controlled formats.

Reading an Entire File Line by Line

Combining Scanner with a File and hasNextLine() gives you a clean pattern for reading text files without dealing with BufferedReader:

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class ReadFile {
    public static void main(String[] args) throws FileNotFoundException {
        File file = new File("log.txt");
        try (Scanner sc = new Scanner(file)) {
            int lineNum = 0;
            while (sc.hasNextLine()) {
                lineNum++;
                String line = sc.nextLine();
                System.out.printf("%3d: %s%n", lineNum, line);
            }
        }
    }
}

Note: The try-with-resources syntax (available since Java 7) automatically closes the Scanner even if an exception is thrown — always prefer it over a manual finally block.

Under the Hood

Scanner is built on top of Java’s java.util.regex engine. Every call to next*() works in two phases:

  1. Skip leading delimiter — it advances past any characters that match the current delimiter pattern (default \p{javaWhitespace}+).
  2. Match a token — it applies a type-specific pattern (e.g., [-+]?[0-9]+ for integers) and hands the matched text to the appropriate parser (Integer.parseInt, Double.parseDouble, etc.).

Because regex matching runs on every token, Scanner is not the fastest way to read large files. For high-throughput line-by-line reading, BufferedReader with manual parsing is typically 2–5× faster. For parsing raw bytes or binary data, use DataInputStream.

Scanner is also not thread-safe. If multiple threads must read from the same source, synchronise externally or use separate Scanner instances.

Memory Footprint

Scanner holds only the portion of the input needed for the current token match — it does not buffer entire lines by default (unlike BufferedReader). For large files this keeps memory usage low, but it also means each read may trigger more underlying I/O calls unless you wrap the file in a BufferedInputStream first:

// Faster file scanning for large files
try (Scanner sc = new Scanner(
        new java.io.BufferedInputStream(new java.io.FileInputStream("big.txt")))) {
    while (sc.hasNextLine()) {
        process(sc.nextLine());
    }
}

Quick Reference: Scanner vs BufferedReader

FeatureScannerBufferedReader
Packagejava.utiljava.io
Typed parsingYes (nextInt(), etc.)No — manual
Line readingnextLine()readLine()
Delimiter controlYes (regex)No
PerformanceModerateFast
Thread-safeNoNo
Best forInteractive input, simple parsingFast line-by-line file reads
  • BufferedReader — faster line-by-line reading for large files
  • Console — secure password input and formatted I/O for interactive console apps
  • DataInputStream — reading primitive types from binary streams
  • FileReader — the underlying character stream Scanner wraps when reading text files
  • Regex — understand the patterns Scanner uses for token matching and custom delimiters
  • Java I/O — overview of the entire Java I/O framework
Last updated June 13, 2026
Was this helpful?