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:
| Source | Constructor |
|---|---|
| Standard input (keyboard) | new Scanner(System.in) |
| A file | new Scanner(new File("data.txt")) |
| A string | new 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 checkedFileNotFoundException, 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:
| Method | Returns | Reads until |
|---|---|---|
next() | String | next whitespace-delimited token |
nextLine() | String | end of the current line |
nextInt() | int | next token parsed as int |
nextLong() | long | next token parsed as long |
nextDouble() | double | next token parsed as double |
nextFloat() | float | next token parsed as float |
nextBoolean() | boolean | true 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()afternextInt()/nextDouble()is the single most frequentScannerbug. 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.
Scannerwith 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
finallyblock.
Under the Hood
Scanner is built on top of Java’s java.util.regex engine. Every call to next*() works in two phases:
- Skip leading delimiter — it advances past any characters that match the current delimiter pattern (default
\p{javaWhitespace}+). - 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
| Feature | Scanner | BufferedReader |
|---|---|---|
| Package | java.util | java.io |
| Typed parsing | Yes (nextInt(), etc.) | No — manual |
| Line reading | nextLine() | readLine() |
| Delimiter control | Yes (regex) | No |
| Performance | Moderate | Fast |
| Thread-safe | No | No |
| Best for | Interactive input, simple parsing | Fast line-by-line file reads |
Related Topics
- 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