Scanner vs BufferedReader in Java: Reading Console Input
Read standard input in Java with Scanner for convenience or BufferedReader for speed. The nextLine after nextInt trap, printf format specifiers and fast output.
- Course: Java study plan
- Module: Java & the JVM
- Kind: Lesson
- Reading time: 16 min
- Runtime: OpenJDK 18
How do you read input in Java?
To read input in Java, wrap System.in in a Scanner and call nextInt(), next() or nextLine(), which read whitespace-separated tokens or whole lines. For large inputs use a BufferedReader, whose readLine() returns one line at a time, or null at end of input, and parse numbers with Integer.parseInt; it is roughly ten times faster than Scanner.
Lesson
Every exercise in this track is a program that reads from standard input and writes to standard output. That is also how competitive programming, coding-round harnesses and most command-line tools work, so it is worth learning properly rather than copying a snippet. This lesson covers the two readers you will use — Scanner for convenience, BufferedReader for speed — and the output methods, with the exact behaviours that trip people up.
Standard streams
The JVM gives every program three streams:
System.in— anInputStreamof raw bytes from the keyboard, a pipe, or a file redirected with<.System.out— aPrintStreamfor normal output.System.err— aPrintStreamfor errors and diagnostics. The judge compares onlySystem.out; anything you print toSystem.erris shown to you but never marked wrong. Use it for debugging.
Scanner: tokens, not lines
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
long total = 0;
for (int i = 0; i < n; i++) {
total += in.nextLong();
}
System.out.println(total);
}
}
A Scanner splits input into tokens separated by whitespace (spaces, tabs, newlines — any amount). nextInt(), nextLong(), nextDouble(), next() (one word) each consume one token, skipping whitespace before it. hasNext() / hasNextInt() tell you whether another token exists without consuming it — the standard way to read "until end of input":
while (in.hasNextInt()) {
process(in.nextInt());
}
The nextLine() trap
nextLine() reads the rest of the current line, up to and including the newline, and returns it without the newline. Mixed with token methods it produces the most common Scanner bug:
int age = in.nextInt(); // reads "30", leaves "\n" in the buffer
String name = in.nextLine(); // reads the rest of THAT line: "" (empty!)
After nextInt() the cursor sits just before the newline that ended the number; nextLine() returns the empty string before it. Fixes: call in.nextLine() once to discard the leftover, or read everything as lines and parse them yourself.
Type mismatches
nextInt() on a token that is not an integer throws InputMismatchException; on no token at all, NoSuchElementException. In exercises the input is well-formed, so these mean your reading order is wrong, not the input.
Locale
nextDouble() uses the default locale: on a German system it expects 3,14. Judges run in the C/English locale, so 3.14 works; in production code create the scanner with new Scanner(System.in).useLocale(Locale.US) if you must accept dotted decimals everywhere.
BufferedReader: lines, fast
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
StringTokenizer st = new StringTokenizer(br.readLine());
long total = 0;
for (int i = 0; i < n; i++) {
total += Long.parseLong(st.nextToken());
}
System.out.println(total);
}
}
readLine() returns the next line without its terminator, or null at end of input — the idiom for "read all lines":
String line;
while ((line = br.readLine()) != null) {
…
}
Numbers are parsed with Integer.parseInt, Long.parseLong, Double.parseDouble; a line with several numbers is split with StringTokenizer (fastest) or line.split(" ") (fine for small input; beware of double spaces producing empty tokens — line.trim().split("\\s+") is the safe form).
Why bother? Scanner uses regular expressions and is roughly ten times slower than BufferedReader. For a thousand numbers nobody notices; for a million, Scanner is the difference between passing and timing out.
readLine() declares IOException, a checked exception (Module 12). Until then, adding throws IOException to main is the accepted way to let it through.
Output: println, print, printf
System.out.println("total = " + total); // string then newline
System.out.print(x); // no newline
System.out.print(' ');
System.out.printf("%.2f%n", 3.14159); // 3.14 then a newline
System.out.printf("%5d|%-5d|%05d%n", 42, 42, 42); // " 42|42 |00042"
Format specifiers you will use: %d integer, %s string (calls toString), %f float (default 6 decimals), %.2f two decimals, %n newline, %5d right-aligned width 5, %-5s left-aligned, %,d thousands separators, %x hex, %c char, %b boolean, %e scientific. String.format(...) returns the same text instead of printing it.
Two newline facts: println writes the platform line separator (\n on Linux, \r\n on Windows); "\n" in a string is always a bare linefeed. The judge normalises trailing whitespace and CRLF, so either is safe here; in production, prefer %n or System.lineSeparator() in files meant to be portable.
Fast output
System.out.println flushes on every call when connected to a terminal and, through PrintStream's synchronisation, is slow for hundreds of thousands of lines. The remedy is to build the output first:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
sb.append(result[i]).append('\n');
}
System.out.print(sb);
or wrap the stream: PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out))); … out.flush(); at the end — forgetting flush() (or close()) loses the output entirely, a bug that produces a mysterious empty result.
Reading a whole input at once
Sometimes the simplest approach is to slurp everything:
String all = new String(System.in.readAllBytes()).trim();
String[] tokens = all.split("\\s+");
readAllBytes() (Java 9+) reads to end of stream. Good for small inputs and for problems where the format is "some numbers, in any layout".
A template for the exercises
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder out = new StringBuilder();
// read, compute, append to out
System.out.print(out);
}
}
The class must be named Main on the runner. Read with br.readLine(), split with trim().split("\\s+"), parse with Integer.parseInt, append results to out, print once.
Key takeaways
Scannerreads whitespace-separated tokens; mixingnextInt()andnextLine()leaves a newline behind.BufferedReader.readLine()returnsnullat end of input and is ~10× faster thanScanner.printf/String.formatfor formatting;%.2f,%d,%s,%ncover most needs.- For big outputs, build a
StringBuilderand print once; if you wrap in aPrintWriter, flush it.
Common questions
What is the difference between Scanner and BufferedReader in Java?
Scanner splits input into whitespace-separated tokens and converts them to numbers for you, but uses regular expressions and is roughly ten times slower. BufferedReader only reads lines, returning null at end of input, so you split and parse them yourself; it is the choice for large inputs.
Why is nextLine() skipped after nextInt() in Java?
It is not skipped: nextInt() reads the number and leaves the line break after it, so the next nextLine() returns the empty rest of that line. Call in.nextLine() once to discard the leftover, or read every line with nextLine() and parse it yourself.
How do I print a number with two decimal places in Java?
Use System.out.printf("%.2f%n", value) to print it, or String.format("%.2f", value) to get the text; %n adds a newline. Other common specifiers are %d for integers, %s for strings, %5d for a right-aligned width and %,d for thousands separators.
How do I read input until end of file in Java?
With BufferedReader, loop while ((line = br.readLine()) != null), since readLine() returns null at end of input. With Scanner, loop while (in.hasNextInt()) or while (in.hasNext()), which check for another token without consuming it.
Why does my PrintWriter print nothing?
A PrintWriter wrapped around a BufferedWriter holds output in memory until it is flushed. If the program ends without out.flush() or out.close(), the buffered text is lost and the output is empty; flush once at the end.
Exercises
Sum and average
Read an integer n followed by n integers (whitespace-separated, across any number of lines). Print the sum on the first line and the average, rounded to two decimal places, on the second.
Input: n, then n integers. n is at least 1. Output: two lines: sum=<sum> and avg=<average with 2 decimals>.
Example: input 4 10 20 30 41 →
sum=101
avg=25.25Lines, reversed and numbered
Read every line of standard input until the end (there may be blank lines — keep them). Print the lines in reverse order, each prefixed with its original line number right-aligned in 3 characters and a colon, then total lines: <n>. Use a BufferedReader and printf.
Example input
alpha
beta
gamma
→
4: gamma
3:
2: beta
1: alpha
total lines: 4In this module: Java & the JVM
← Packages, imports and the class library · Checkpoint — Java & the JVM →