Console & standard streams in Java
System.in/out/err, BufferedReader vs Scanner performance.
nextInt(), then a name with nextLine(). The name comes back empty — the program didn't even wait for you to type. Ghost input?Three pipes
Every program gets three standard streams: **System.in** (bytes typed or piped in — an InputStream), **System.out (normal output) and System.err** (errors and diagnostics) — both PrintStreams. They're separate: in a shell, > redirects stdout and 2> redirects stderr.
Scanner vs BufferedReader
**Scanner** is convenient — nextInt(), nextLine() — but it tokenizes with regular expressions and is slow on big input. **BufferedReader.readLine() plus Integer.parseInt** is much faster.
var in = new BufferedReader(
new InputStreamReader(System.in));
String line = in.readLine();
System.err.println("debug: " + line);The ghost line
What does this print?
var sc = new Scanner("7 8\nhello");
int a = sc.nextInt();
int b = sc.nextInt();
String rest = sc.nextLine();
System.out.println("[" + rest + "]");[hello][][7 8]
Show the answer
[] — nextInt() stops right after the number and leaves the line break behind. nextLine() returns the rest of that same line: empty.
Fixing the ghost line
After nextInt(), call **nextLine() once to consume the rest of the line**, then read the real line. Or read whole lines with nextLine()/readLine() and parse numbers yourself.
int age = sc.nextInt();
sc.nextLine(); // eat line end
String name = sc.nextLine(); // real inputClosing System.in
Closing a Scanner **also closes System.in — and the standard input can't be reopened**. The next Scanner(System.in) throws **NoSuchElementException. Create one** Scanner for the program and don't close it.
int askNumber() {
try (var sc = new Scanner(System.in)) {
return sc.nextInt();
} // closes System.in forever!
}Reading one million numbers
var sc = new Scanner(System.in);
for (int i = 0; i < n; i++) {
sum += sc.nextInt();
}Regex-based tokenizing for every number: slow.
var br = new BufferedReader(
new InputStreamReader(System.in));
for (int i = 0; i < n; i++) {
sum += Integer.parseInt(br.readLine());
}Big chunked reads and cheap parsing.
Pipes on the job
Command-line tools write results to stdout and errors to stderr so scripts can pipe one and log the other; containers collect both as logs. Competitive programmers switch from Scanner to BufferedReader when big inputs time out.
Key takeaways
- System.out and System.err can be redirected separately
- Scanner: easy tokens, but regex-based and slow
- BufferedReader.readLine(): fast for large input
- nextInt() leaves the rest of the line unread
On Unix-like systems the three streams have fixed file descriptor numbers: 0 for stdin, 1 for stdout, 2 for stderr — that's where the 2> in shell redirection comes from.
Practice questions
What does this print?
var sc = new Scanner("42\nworld");
int n = sc.nextInt();
String line = sc.nextLine();
System.out.println(n + "[" + line + "]");- 42[world]
- 42[]
- 42[42]
- Throws InputMismatchException
Check your answer
42[]. nextInt reads only "42" and leaves the line break behind. nextLine then returns the rest of that line: an empty string.
A program reading one million numbers from System.in with Scanner is too slow. What's the usual fix?
- Read with BufferedReader and parse with Integer.parseInt
- Call System.in.reset() between numbers
- Use System.console().readLine() for each number
- Read with Scanner in a parallel stream
Check your answer
Read with BufferedReader and parse with Integer.parseInt. Scanner tokenizes with regular expressions and does a lot of checking per token. BufferedReader reads big chunks and parsing manually is far cheaper.