☕ Java

Console Input

The System.console() method returns a Console object that provides direct access to the character-based console (terminal) attached to the JVM. Its primary advantage over Scanner and BufferedReader is the readPassword() method, which reads input without echoing characters to the screen — essential for collecting passwords and other sensitive data securely.

The Console Class

System.console() returns the unique Console instance associated with the JVM, or null if the JVM is not connected to a console — which happens when input or output is redirected (e.g. in IDE run configurations, piped commands, or automated tests). Always null-check before using Console. Console is not available in most IDE environments during development.
Java
import java.io.Console;

public class ConsoleExample {
    public static void main(String[] args) {

        // ── Get the Console instance: ─────────────────────────────────
        Console console = System.console();

        // ── ALWAYS null-check — not available in all environments: ────
        if (console == null) {
            System.err.println("No console available.");
            System.err.println("Run from a terminal, not from an IDE.");
            System.exit(1);
        }

        // ── Read a line of text: ──────────────────────────────────────
        String name = console.readLine("Enter your name: ");
        System.out.println("Hello, " + name);

        // ── Read formatted prompt: ────────────────────────────────────
        String city = console.readLine("Enter city for %s: ", name);
        System.out.println("City: " + city);

        // ── Read an integer (readLine returns String — must parse): ───
        int age = Integer.parseInt(
            console.readLine("Enter age: ").trim());
        System.out.println("Age: " + age);

        // ── Write to console: ─────────────────────────────────────────
        console.printf("Welcome, %s from %s!%n", name, city);
        console.writer().println("Using the console writer.");
        console.flush();
    }
}

readPassword() — Secure Input

readPassword() reads input without displaying the characters on screen — the terminal echoing is disabled for the duration of the call. It returns a char[] rather than a String. This is intentional: String objects are immutable and remain in memory until garbage collected, while a char[] can be explicitly zeroed out immediately after use, reducing the window during which the password exists in memory.
Java
import java.io.Console;
import java.util.Arrays;

public class SecurePasswordInput {
    public static void main(String[] args) {

        Console console = System.console();
        if (console == null) {
            System.err.println("No console — run from terminal.");
            return;
        }

        // ── Read password — characters not echoed to screen: ─────────
        char[] password = console.readPassword("Enter password: ");
        // User types their password — nothing appears on screen

        // ── Use the password (validate, hash, etc.): ──────────────────
        boolean valid = validatePassword(password);

        // ── CRITICAL: zero out the password array immediately after use: ─
        Arrays.fill(password, '');
        // password array now contains all null characters
        // The actual password value no longer exists in memory

        if (valid) {
            console.printf("Login successful.%n");
        } else {
            console.printf("Invalid password.%n");
        }
    }

    private static boolean validatePassword(char[] input) {
        char[] correct = "secret123".toCharArray();
        boolean match = Arrays.equals(input, correct);
        Arrays.fill(correct, '');   // zero out the reference too
        return match;
    }
}

// ── readPassword with formatted prompt: ──────────────────────────────
char[] pwd = console.readPassword("Password for %s: ", username);

// ── Why char[] instead of String: ────────────────────────────────────
//
//  String password = new String(console.readPassword(...));
//
//  Problems with String:
//  1. Strings are immutable — cannot be overwritten in memory
//  2. String may be interned in the String pool
//  3. Remains in heap until GC decides to collect it
//  4. May appear in heap dumps, thread dumps, or logs
//
//  char[] solution:
//  1. Can be zeroed: Arrays.fill(pwd, '')
//  2. Password window in memory is minimised
//  3. Standard security practice (recommended by OWASP)

// ── Confirm password example: ────────────────────────────────────────
Console con = System.console();
char[] pwd1 = con.readPassword("New password: ");
char[] pwd2 = con.readPassword("Confirm password: ");

if (Arrays.equals(pwd1, pwd2)) {
    con.printf("Password set successfully.%n");
} else {
    con.printf("Passwords do not match.%n");
}

Arrays.fill(pwd1, '');
Arrays.fill(pwd2, '');

Console Methods Reference

Console provides a small focused API. It is not a general-purpose I/O class — it is specifically designed for interactive terminal sessions with a human user. For non-interactive input or IDE environments, fall back to Scanner or BufferedReader.
Java
Console console = System.console();

// ── Reading methods: ──────────────────────────────────────────────────

// readLine() — read a line, returns null at end of stream:
String line = console.readLine();

// readLine(fmt, args) — display formatted prompt then read:
String name = console.readLine("Hello %s, enter city: ", "Alice");

// readPassword() — read without echo, returns char[]:
char[] pwd = console.readPassword();

// readPassword(fmt, args) — formatted prompt, no echo:
char[] pwd2 = console.readPassword("Password for %s: ", username);

// ── Writing methods: ──────────────────────────────────────────────────

// printf(fmt, args) — formatted output, returns Console for chaining:
console.printf("Name: %s, Age: %d%n", "Alice", 30);
console.printf("Pi = %.5f%n", Math.PI);

// format(fmt, args) — identical to printf, returns Console:
console.format("Score: %d/%d%n", 85, 100);

// writer() — returns PrintWriter for advanced output:
PrintWriter writer = console.writer();
writer.println("Writing via PrintWriter");
writer.printf("Value: %d%n", 42);

// flush() — flush output buffer:
console.flush();

// ── Chaining console calls: ───────────────────────────────────────────
console.printf("=== Login ===%n")
       .printf("System: %s%n", System.getProperty("os.name"));
String user = console.readLine("Username: ");
char[] pass = console.readPassword("Password: ");

// ── Fallback pattern — Console not available in IDEs: ────────────────
public static String readInput(String prompt) {
    Console console = System.console();
    if (console != null) {
        return console.readLine(prompt);
    } else {
        // Fallback for IDE / non-terminal environments:
        System.out.print(prompt);
        return new Scanner(System.in).nextLine();
    }
}

Complete Login Example

A complete interactive terminal login demonstrates all Console features together — formatted prompts, secure password reading, validation, retry logic, and zeroing sensitive data after use.
Java
import java.io.Console;
import java.util.Arrays;

public class TerminalLogin {

    private static final int MAX_ATTEMPTS = 3;

    // Simulated user store — in reality, store hashed passwords:
    private static final String VALID_USER = "admin";
    private static final char[] VALID_PASS = "p@ssw0rd".toCharArray();

    public static void main(String[] args) {
        Console console = System.console();
        if (console == null) {
            System.err.println("Must run from a terminal.");
            System.exit(1);
        }

        console.printf("=== Secure Login ===%n%n");

        for (int attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {

            String username = console.readLine("Username: ");
            char[] password = console.readPassword("Password: ");

            try {
                if (authenticate(username, password)) {
                    console.printf("%nLogin successful. Welcome, %s!%n",
                        username);
                    startSession(username, console);
                    return;
                } else {
                    int remaining = MAX_ATTEMPTS - attempt;
                    if (remaining > 0) {
                        console.printf(
                            "Invalid credentials. %d attempt(s) remaining.%n%n",
                            remaining);
                    } else {
                        console.printf(
                            "Too many failed attempts. Account locked.%n");
                    }
                }
            } finally {
                // Always zero the password array — even if exception thrown:
                Arrays.fill(password, '');
            }
        }
    }

    private static boolean authenticate(String user, char[] pass) {
        return VALID_USER.equals(user) && Arrays.equals(VALID_PASS, pass);
    }

    private static void startSession(String user, Console console) {
        console.printf("%nEnter commands (type 'exit' to quit):%n");
        String command;
        while ((command = console.readLine("> ")) != null) {
            if ("exit".equalsIgnoreCase(command.trim())) {
                console.printf("Goodbye, %s!%n", user);
                break;
            }
            console.printf("Executing: %s%n", command);
        }
    }
}