Java Console Input and Output: System.out, Console and IO

Java console input and output with System.out, System.err, printf, Scanner, Java 25 IO, the Console class, hidden passwords and the null console case.

Diagram of a Java process with System.in from the keyboard or a file, System.out to the terminal or a file, System.err to the terminal, and Console available only when the process is attached to a terminal

Console input and output in Java means reading the text a user types in a terminal and writing text back to that terminal, either through the standard streams System.in, System.out and System.err, or through the java.io.Console object that System.console() returns. Java 25 adds the java.lang.IO class with short println() and readln() methods on top of the standard streams.

We use console I/O in command-line tools, admin scripts, small utilities and interview-style programs, and in any program that prompts for a password or prints a report to the terminal. The following example writes a report line and an error message, and checks whether a terminal is attached.

IO.println("Expenses for March");                    // prints Expenses for March
System.out.printf("%-8s %7.2f%n", "Coffee", 3.5);     // prints "Coffee      3.50"
System.err.println("No receipt for Taxi");            // prints to the error stream
Console console = System.console();                   // null when stdin or stdout is redirected
boolean interactive = console != null;                // false in a pipe, an IDE or a cron job

Notice that the program asks for the console before using it, because System.console() returns null whenever no terminal is attached. We start with the output methods, separate standard output from the error stream, read input, and work through the Console class, including password prompts and the null case.

1. Writing Output to the Console

The field System.out is a PrintStream connected to standard output. Its print() method writes text as it is, println() adds a line separator, and printf() or format() fills a format string with arguments. Since Java 25, IO.println() and IO.print() write to the same standard output with less typing.

String item = "Coffee";
double amount = 3.5;
String line = String.format("%-8s %7.2f", item, amount);    // "Coffee      3.50"
String total = "Total: %.2f".formatted(12.75);             // "Total: 12.75"

We print such a line with System.out.println(line), or with System.out.printf(“%-8s %7.2f%n”, item, amount) in one step. The %n specifier writes the line separator of the operating system, and printf() adds no line break on its own. The printf formatting guide lists every flag and conversion.

User input must always be an argument of printf(), never the format string itself. A note such as 50% off that a user typed contains a percent sign, and printf() reads it as a format specifier.

String note = "50% off";
String bad = String.format(note);              // MissingFormatArgumentException: Format specifier '% o'
String safe = String.format("Note: %s", note); // "Note: 50% off"

2. Standard Output vs the Error Stream

A Java process has three standard streams. The program reads from System.in, writes normal results to System.out and writes warnings and errors to System.err. Both output streams appear in the same terminal window, but the shell can send them to different places.

Diagram of a Java process with System.in from the keyboard or a file, System.out to the terminal or a file, System.err to the terminal, and Console available only when the process is attached to a terminal
System.out and System.err can be redirected separately, while System.console() exists only when both input and output are a terminal
# results go to report.txt, errors stay visible in the terminal
java ExpenseReport > report.txt

# results and errors in two files
java ExpenseReport > report.txt 2> errors.txt

Keeping the two apart matters as soon as another program reads our output. A script that runs java ExpenseReport | sort sorts only the report lines, and a warning printed with System.err never ends up inside the sorted data. For applications that run as services, a logging framework replaces both streams.

3. Reading Input From the Console

Input arrives on System.in as bytes, so we wrap it in a class that turns the bytes into lines, words or numbers. The detailed guide to reading input from the console compares them, including the nextLine() skip after nextInt().

  • The Scanner class splits input into tokens and parses numbers with nextInt() and nextDouble(), and hasNextDouble() checks the input first.
  • The IO.readln() method from Java 25 reads one line, with an optional prompt, and returns null at the end of input.
  • The BufferedReader class reads whole lines fast, which suits large piped input.
  • The Console class reads lines and passwords from the terminal, as we see in section 4.

The safe pattern checks the input before parsing it, so a user who types abc gets a message instead of an InputMismatchException.

Scanner scanner = new Scanner("abc\n12.50\n");       // new Scanner(System.in) in a real program
boolean validFirst = scanner.hasNextDouble();          // false, "abc" is not a number
String skipped = scanner.nextLine();                   // "abc"
double amount = scanner.nextDouble();                  // 12.5

4. Reading and Writing With the Console Class

The Console class represents the terminal itself, not a stream. It reads and writes characters in the charset of the terminal, reads passwords without showing them, and combines a prompt with the read in one call. There is at most one Console object per JVM, and System.console() returns it.

MethodWhat it doesSince
readLine(), readLine(fmt, args)Reads one line, optionally after a formatted prompt; returns null at the end of input6
readPassword(), readPassword(fmt, args)Reads one line with echo turned off and returns a char[]6
printf(fmt, args), format(fmt, args)Writes formatted text to the terminal and returns the Console6
reader(), writer()Return the Reader and PrintWriter of the terminal, for example for a Scanner6
charset()Returns the charset the console uses for reading and writing17
isTerminal()Returns true when the console is an interactive terminal22
readLine(Locale, fmt, args) and other Locale overloadsFormat the prompt with a given locale23

A prompt and the answer take one line of code, and printf() returns the console, so calls can be chained.

static void askName(Console console) {
    String name = console.readLine("Your name: ");
    if (name == null) {                 // end of input, e.g. Ctrl+D
        return;
    }
    console.printf("Hello %s%n", name.strip()).flush();
}

Closing a Scanner built on console.reader() leaves the console usable, because that reader ignores close(). Closing a Scanner built on System.in closes System.in for the rest of the program, so we create one scanner for the whole program and leave it open.

5. Reading a Password Without Echo

The method readPassword() turns off the echo of the terminal while the user types, so the secret does not appear on the screen or in a screen recording. The text is not encrypted, it is only hidden. The method returns a char[] instead of a String, so we can overwrite the characters after use.

Say an expense tool uploads the monthly report to an accounting service and needs an API token. People run it by hand in a terminal, and the build server runs it every night without a terminal. The tool reads the token with readPassword() when a console exists and from an environment variable otherwise, and it never prints the token.

static char[] readToken() {
    Console console = System.console();
    if (console != null) {
        char[] token = console.readPassword("API token: ");
        return token != null ? token : new char[0];
    }
    String fromEnv = System.getenv("EXPENSES_TOKEN");    // set by the build server
    return fromEnv != null ? fromEnv.toCharArray() : new char[0];
}
char[] token = readToken();
try {
    // 1. Use the token, e.g. in an Authorization header
} finally {
    Arrays.fill(token, ' ');                              // 2. Overwrite the secret
}
int length = token.length;                                // 0 when no token was given

Overwriting the array shortens the time the secret stays in memory, but it is not a guarantee, because the token may have been copied before, for example into a String of an HTTP library.

6. When System.console() Returns null

On JDK 25, System.console() returns null whenever standard input or standard output is not a terminal. Started in a terminal, a program gets a console whose isTerminal() returns true. Started with < input.txt or with | cat, it gets null.

The console is also missing in these common setups, because each of them connects the program to pipes or files instead of a terminal.

  • The run window of an IDE such as IntelliJ IDEA or Eclipse, which connects the program to pipes instead of a terminal.
  • A command with redirected input or output, such as java App < data.txt or java App | tee log.txt.
  • A scheduled job, a system service or a CI pipeline step.
  • A Docker container started without the -it options.

A program that needs both cases falls back to the standard streams, as the token example did. The method ask() asks for a line through the console when one exists and through IO.readln() otherwise, so it also works with piped input and in tests.

static String ask(String prompt) {
    Console console = System.console();
    return console != null ? console.readLine("%s", prompt) : IO.readln(prompt);
}

A call such as ask(“Category: “) returns the typed line, or null when the input has ended. Notice that the prompt goes into readLine() as an argument of %s, which keeps a percent sign in the prompt text from being read as a format specifier.

7. Choosing Between the Console Options

Every option writes to or reads from the same terminal in an interactive run, so the choice depends on what else the program must handle, such as redirection, passwords or parsing numbers.

NeedUseReason
Print resultsSystem.out or IO.println()Works with redirection and pipes
Print warnings and errorsSystem.err or a loggerStays out of redirected results
Read numbers and wordsScanner on System.inParses and validates tokens
Read lines in Java 25IO.readln()Short, prompt included, null at end of input
Read a passwordConsole.readPassword()Turns off echo, returns char[]
Run in IDEs, pipes and jobsStandard streams, with Console as an optionSystem.console() can be null

8. Java Console Input and Output FAQs

A terminal, an IDE run window and a script give a Java program different streams, and that difference explains the first answer and several others.

8.1. Why does System.console() return null in IntelliJ IDEA or Eclipse?

The IDE starts the program with its input and output connected to pipes, not to a terminal, so the JVM has no console device. We run the program from a terminal, for example the terminal tab of the IDE, or we fall back to System.in and System.out as in section 6.

8.2. Should we close System.out, System.in or the Console?

No. These streams belong to the whole JVM, and after System.out.close() every later println() call in the program prints nothing. The JVM flushes and releases them when it exits.

8.3. How do we print colored text to the console?

We write ANSI escape sequences, such as “\u001B[31m” for red and “\u001B[0m” to reset. Linux and macOS terminals and Windows Terminal support them, whereas a redirected file receives the raw codes, so we add colors only when System.console() is not null.

String red = "\u001B[31m" + "Over budget" + "\u001B[0m";   // shows red text in a terminal

8.4. What is the difference between Console.readLine() and IO.readln()?

Both read one line and return null at the end of input. The Console method works only when a terminal is attached and formats its prompt, whereas IO.readln() reads from System.in in every environment, including pipes and IDEs.

9. Conclusion

Console programs write results to System.out or with IO.println(), keep errors on System.err, and pass user text to printf() only as an argument. For input, Scanner and IO.readln() work in every environment.

The Console class adds prompts and hidden password input, but it exists only when the program runs in a terminal. Checking System.console() for null and falling back to the standard streams keeps the same program working in the IDE, in pipes and in scheduled jobs. Other beginner programs are in the Java examples collection.

10. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.