Chapter 2: Java Prerequisites for DSA
2.06Beginner8 topics14 min

Input-output for algorithms

Fast input and output matter when n reaches 10⁵ and above. This lesson compares Scanner and BufferedReader, shows StringTokenizer and a custom byte parser, buffered output, end-of-input handling and multiple test cases.

Learning goals

  • Read large inputs quickly
  • Write large outputs with a single flush
  • Handle EOF and multi-test input correctly

Prerequisites

Java language essentialsCore library utilities
2.06.1

Scanner vs BufferedReader

Scanner is convenient (nextInt, nextLine) but slow because it parses with regular expressions. Reading 10⁶ numbers can take seconds. BufferedReader reads big chunks and returns whole lines as strings, and is several times faster.

Use Scanner for small inputs and learning; use BufferedReader or a custom reader when n is large.

Java
1BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
2int n = Integer.parseInt(br.readLine().trim());
3StringTokenizer st = new StringTokenizer(br.readLine());
4int[] a = new int[n];
5for (int i = 0; i < n; i++) a[i] = Integer.parseInt(st.nextToken());
2.06.2

StringTokenizer

StringTokenizer splits a line on whitespace without regular expressions. Combined with BufferedReader it is the usual fast reader. When tokens may continue onto the next line, refill the tokenizer lazily.

String.split(" ") is simpler but allocates an array per line and can be slower on very large input.

Java
1static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
2static StringTokenizer st;
3static String next() throws IOException {
4 while (st == null || !st.hasMoreTokens()) {
5 String line = br.readLine();
6 if (line == null) return null; // EOF
7 st = new StringTokenizer(line);
8 }
9 return st.nextToken();
10}
11static int nextInt() throws IOException { return Integer.parseInt(next()); }
2.06.3

Fast input parser

The fastest approach reads bytes from System.in into a buffer and parses numbers by hand, avoiding intermediate String objects. It handles negative numbers and skips whitespace. Use it when reading millions of integers.

Keep the buffer in a field and refill when exhausted.

Java
1static final InputStream in = System.in;
2static final byte[] buf = new byte[1 << 16];
3static int len = 0, ptr = 0;
4static int read() throws IOException {
5 if (ptr == len) { len = in.read(buf, 0, buf.length); ptr = 0; if (len <= 0) return -1; }
6 return buf[ptr++];
7}
8static int readInt() throws IOException {
9 int c = read();
10 while (c != '-' && (c < '0' || c > '9')) c = read();
11 boolean neg = false;
12 if (c == '-') { neg = true; c = read(); }
13 int x = 0;
14 while (c >= '0' && c <= '9') { x = x * 10 + (c - '0'); c = read(); }
15 return neg ? -x : x;
16}
2.06.4

PrintWriter

System.out.println flushes frequently and is slow for large output. Wrap standard output in a PrintWriter over a BufferedWriter (or BufferedOutputStream), print as you go, and call flush() or close() once at the end.

Forgetting to flush loses the output.

Java
1PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
2for (int i = 0; i < 5; i++) out.println(i * i);
3out.flush();
2.06.5

BufferedWriter

BufferedWriter collects writes in memory and sends them in large blocks. It only writes strings and characters, so convert numbers with String.valueOf or Integer.toString, and write line breaks yourself.

Choose PrintWriter for convenience (println, printf) and BufferedWriter for the lowest overhead.

Java
1BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
2for (int i = 0; i < 3; i++) { bw.write(Integer.toString(i)); bw.newLine(); }
3bw.flush();
2.06.6

Standard input and output

Standard input (System.in), output (System.out) and error (System.err) are the three standard streams. Judges read stdin and compare stdout, so debug output must go to System.err or be removed.

In a terminal, redirect a file as input with java Main < input.txt and capture output with > out.txt.

Java
1System.out.println("answer"); // graded
2System.err.println("debug: n=" + 5); // ignored by the judge
3// run: java Main < in.txt > out.txt
2.06.7

EOF

End of file means no more input. BufferedReader.readLine() returns null at EOF, Scanner.hasNext() returns false, and a byte read() returns -1. Use these to read “until the input ends” instead of counting.

Always handle a possible null line before calling methods on it.

Java
1BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
2String line;
3long total = 0;
4while ((line = br.readLine()) != null) {
5 line = line.trim();
6 if (line.isEmpty()) continue;
7 total += Long.parseLong(line);
8}
9System.out.println(total);
2.06.8

Multiple test cases

Many problems start with the number of test cases t, followed by t independent inputs. Read t, then loop, resetting all per-case state inside the loop. Leaking state (a static counter, a reused array) from one case into the next is a common bug.

Collect all answers in one StringBuilder and print once at the end.

Java
1int t = readInt();
2StringBuilder sb = new StringBuilder();
3while (t-- > 0) {
4 int n = readInt();
5 long sum = 0; // reset for every test case
6 for (int i = 0; i < n; i++) sum += readInt();
7 sb.append(sum).append('\n');
8}
9System.out.print(sb);

Practice ladder

Now try it yourself

Easy

  • Read n then n integers with BufferedReader and print their sum
  • Print the squares of 1 to 10 using one flush

Medium

  • Read integers until EOF and print their maximum
  • Write the multi-test skeleton for “read n and n numbers, print the sum”

Advanced

  • Implement a byte-based reader that also parses longs and doubles and compare its speed with Scanner on 10⁶ numbers

Key takeaways

  • Scanner is slow; use BufferedReader with StringTokenizer, or a byte reader, for large inputs.
  • Buffer the output and flush once; debug prints go to System.err.
  • Detect EOF with null or -1 and reset state per test case.