AlgoInsight

Free lesson · Java Basic To Advance

Input Output

Easy6 min readjava

Reading and Writing the Console

Every program needs to talk to the outside world. The most fundamental form is reading from the keyboard and writing to the console. This Topic covers Java's I/O basics — System.out, Scanner, and the variants you'll see in real code and interview problems.

File I/O, networking, and more sophisticated streams come in later modules. This Topic is about the everyday console I/O you'll use in coding interviews and quick utilities.

Standard Output: System.out

Java's primary output mechanism is System.out, an instance of PrintStream. The most common methods:

System.out.print("Hello");          // prints with no newline
System.out.println("Hello");         // prints with newline
System.out.printf("%d items%n", 5); // formatted output

The three forms cover most needs:

print() — outputs the argument with no trailing newline. The next print continues on the same line. Useful for building output across multiple statements or for prompts.

System.out.print("Enter name: ");
String name = readLine();
System.out.print("Hello, ");
System.out.println(name);

println() — outputs followed by a newline. The most common method. Works with any type:

System.out.println("text");
System.out.println(42);
System.out.println(3.14);
System.out.println(true);
System.out.println(new int[]{1, 2, 3});  // prints "[I@1540e19d" (the array's hashCode)

The last line is a surprise — arrays print their reference identity, not their contents. Use Arrays.toString() instead:

System.out.println(Arrays.toString(new int[]{1, 2, 3}));  // "[1, 2, 3]"
System.out.println(Arrays.deepToString(matrix));          // for 2D arrays

printf() — formatted output with placeholders. Useful for aligned columns, controlled decimal places, padding:

System.out.printf("Name: %s, Age: %d%n", "Olena", 35);
System.out.printf("Pi: %.4f%n", 3.14159);                // "Pi: 3.1416"
System.out.printf("%-10s %5d%n", "items", 42);           // left-pad name, right-pad number

Common format specifiers:

Specifier Type Example
%s String printf("%s", "text")
%d Integer printf("%d", 42)
%f Float/double printf("%.2f", 3.14)
%n Platform newline printf("line%n")
%b Boolean printf("%b", true)
%c Character printf("%c", 'A')
%e Scientific notation printf("%e", 1234567.0)
%x Hex printf("%x", 255) → "ff"
%-Ns Left-justified, width N printf("%-10s", "hi")
%Nd Right-justified, width N printf("%5d", 42)

Use %n instead of \n for newlines. %n produces the platform-appropriate newline (\r\n on Windows, \n on Linux/Mac). \n is always \n, which can cause display issues in mixed environments.

Interactive animation: print, println and printf with their output - and why %n gives the platform newline where \n does not.

Standard Error: System.err

System.err is a separate stream for error messages. By default it also prints to the console, but it can be redirected separately from standard output:

System.out.println("Normal output");
System.err.println("Error message");

In production, System.err typically goes to a log file or error tracking system. Don't use it for "messages that just happen to indicate errors" — use a proper logging framework (we cover this in Module 26). System.err is for very-low-level errors when no logger is available.

Reading Input: Scanner

The simplest way to read input is the Scanner class:

import java.util.Scanner;

Scanner scanner = new Scanner(System.in);

System.out.print("Name: ");
String name = scanner.nextLine();

System.out.print("Age: ");
int age = scanner.nextInt();

System.out.printf("Hello, %s. You are %d years old.%n", name, age);

scanner.close();

Scanner has methods for each type:

A common gotcha: nextInt() reads the number but leaves the newline character on the buffer. A subsequent nextLine() reads that empty leftover:

int age = scanner.nextInt();          // reads "25"
String name = scanner.nextLine();      // reads "" (the leftover newline)
String realName = scanner.nextLine();  // reads "Olena" (what you actually wanted)

Workarounds:

  1. Consume the leftover newline explicitly: scanner.nextLine(); after each nextInt()
  2. Read everything as nextLine() and parse manually: int age = Integer.parseInt(scanner.nextLine());

The second approach is more reliable and the pattern I recommend for interview code.

graph LR
    A[Standard Streams] --> B[System.in<br/>InputStream<br/>Reading input]
    A --> C[System.out<br/>PrintStream<br/>Normal output]
    A --> D[System.err<br/>PrintStream<br/>Error output]

    B --> E[Wrapped by Scanner<br/>BufferedReader]
    C --> F[print, println, printf]
    D --> F

    style B fill:#7c3aed,color:#fff
    style C fill:#10b981,color:#fff
    style D fill:#dc2626,color:#fff
This diagram shows Java's three standard streams. System.in is an InputStream that reads from the keyboard or piped input. It's typically wrapped by a Scanner or BufferedReader for convenient reading. System.out is a PrintStream for normal output, with methods print, println, and printf. System.err is a separate PrintStream for error output. Standard out and standard error both have the same methods. The separation between out and err is important because they can be redirected independently — you can pipe normal output to a file while leaving errors visible on the console.

Interactive animation: The Scanner trap - nextInt() leaves the newline behind, so reading lines and parsing them is the reliable fix.

Reading Input: BufferedReader

BufferedReader is an older, more efficient alternative for reading text input:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

System.out.print("Name: ");
String name = reader.readLine();

System.out.print("Age: ");
int age = Integer.parseInt(reader.readLine());

BufferedReader is faster than Scanner because it doesn't do type parsing — it just reads strings. You manually parse if you need numbers. For coding interviews where speed matters (large competitive programming inputs), BufferedReader is the preferred choice.

The trade-off: BufferedReader.readLine() throws IOException, which is checked. You either catch it or declare it on your method signature. Scanner's methods don't throw checked exceptions, which makes it slightly more convenient.

Interactive animation: Scanner beside BufferedReader - type parsing and no checked exceptions against raw strings, IOException and speed.

Java 17+ Cleaner Input: Console

For interactive console applications, the Console class provides cleaner input/output:

Console console = System.console();
if (console != null) {
    String name = console.readLine("Name: ");
    char[] password = console.readPassword("Password: ");  // password not echoed
    console.printf("Hello, %s%n", name);
}

Console has the advantage of not echoing passwords (for sensitive input) and being more concise. Caveat: System.console() returns null when running inside an IDE or when input is piped from a file. In those cases, fall back to Scanner.

Output Performance

A note on performance: System.out.println() is slow if called millions of times. Each call:

  1. Synchronizes on the underlying stream (thread safety)
  2. Flushes the buffer
  3. Writes to the OS

For competitive programming or any tight loop generating output, use BufferedWriter or PrintWriter:

import java.io.BufferedWriter;
import java.io.OutputStreamWriter;

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
for (int i = 0; i < 1_000_000; i++) {
    out.write(String.valueOf(i));
    out.newLine();
}
out.flush();

This can be 10-50x faster than equivalent System.out.println() calls. For competitive programming, it's the difference between a correct solution and a time-limit-exceeded answer.

Modern Approach: Reading All Input

For interview problems, sometimes you want to read all input at once and process it:

import java.util.Scanner;

Scanner scanner = new Scanner(System.in);
List<String> lines = new ArrayList<>();
while (scanner.hasNextLine()) {
    lines.add(scanner.nextLine());
}
// process lines...

Or with streams (Java 8+):

import java.io.BufferedReader;
import java.io.InputStreamReader;

List<String> lines = new BufferedReader(new InputStreamReader(System.in))
    .lines()
    .toList();

This is concise and handles all the buffering for you. Good for batch problems where you process everything together.

Common Pitfalls

Warning: Forgetting to close Scanner. Scanner holds a resource (the input stream). Always close it with scanner.close() or use try-with-resources: try (Scanner s = new Scanner(System.in)) { ... }. Failing to close leaks resources.

Mixing nextInt() and nextLine(). The leftover newline causes the next nextLine() to return empty. Use one consistent approach — either always nextLine() and parse, or carefully manage the buffer.

Using \n instead of %n. On Windows, \n produces just LF instead of CRLF, which some terminals display weirdly. %n always does the right thing.

Printing arrays directly. System.out.println(myArray) shows the array's hashCode, not its contents. Use Arrays.toString(myArray).

Closing System.in. scanner.close() on a Scanner wrapping System.in will close System.in. Any subsequent attempt to read input will fail. If you need to use System.in multiple times, don't close the Scanner — let it stay open for the program's lifetime.

Interactive animation: Printing an array directly shows its type and hash - Arrays.toString and Arrays.deepToString print the contents.

Why This Matters in Interviews

Interview: Input/output is rarely the focus of senior interviews, but you need to do it correctly to demonstrate your solution. Reading input wrong wastes interview time. Common pitfalls:

  • Reading numbers and strings mixed (nextInt followed by nextLine)
  • Slow output with millions of println calls
  • Forgetting Arrays.toString() when printing arrays
  • Crashing on EOF (end of input)

For competitive-programming-style problems with large input, knowing the BufferedReader/PrintWriter approach is essential. For typical interview problems, Scanner is fine.

Try It

Exercise: Write a small interactive program that:

  1. Asks the user for their name (with Scanner)
  2. Asks for their age
  3. Asks for their favorite numbers separated by spaces
  4. Prints a formatted summary using printf with aligned columns

Then convert it to use BufferedReader instead of Scanner. Notice the differences in syntax, especially handling the IOException.

Finally, time a million-iteration loop using System.out.println versus BufferedWriter. Notice the performance difference — this is the kind of thing that matters in competitive programming and large-data processing.

Back to Java Basic To Advance