skip to content
everything.basics.consoleIo

reading and printing

System.out, printf formatting, Scanner and IO.println.

chapter
chapter 02.14
reading time
6 min read

print with System.out.println (or, since java 25, IO.println). format with printf / String.format, where a specifier like %,10.2f says exactly how a value should look. read lines with IO.readln (java 25) or a Scanner, and watch out for the classic trap: nextInt() followed by nextLine().

the picture

every program starts with three pipes already plugged in. standard input comes from the keyboard (or whatever you pipe in), standard output goes to the terminal, and standard error goes to the terminal too, but on a separate pipe, so errors still show up when you redirect the normal output to a file.

hover a stage.

hover a stage. java wraps each of the three pipes in an object you get for free. System.err isn't drawn: it's a second, independent output pipe that also ends at the terminal.

printing

Main.java
void main() {
    String name = "duke";
    int count = 3;
    double total = 1234.5;
    System.out.println("hi " + name);
    System.out.print("no newline, ");
    System.out.println("then one");
    System.out.printf("%s bought %d items for $%,.2f%n", name, count, total);
    IO.println("%-6s|%6s|".formatted("left", "right"));
}
output
hi duke
no newline, then one
duke bought 3 items for $1,234.50
left  | right|
methoddoes
System.out.println(x)prints x, then a newline
System.out.print(x)prints x, no newline
System.out.printf(fmt, args...)prints args formatted by fmt
String.format(fmt, args...), fmt.formatted(args...)the same formatting, but returns the String instead of printing (formatted since java 15)
IO.println(x), IO.print(x)java 25 shortcuts, in java.lang, printing through System.out
System.err.println(x)prints to standard error

println can print anything: primitives directly, and objects by calling their toString(). that's why printing an array gives [I@5a4041cc (arrays don't override toString) and printing a List gives [a, b, c] (lists do).

printf and format specifiers

a format string is normal text with specifiers in it. each %... is a slot that gets filled by the next argument, formatted the way the specifier says: %[flags][width][.precision]conversion.

value =
conversion =
flags =
width =
15
precision =
2
String.format("%,15.2f", 1234567.891)
···1,234,567.89
" 1,234,567.89" · 15 characters
% start of a specifier, group thousands15 width: at least 15 characters.2 precision: 2 digits after the pointf fixed-point decimal
pick a value and build a specifier. each character of the result gets its own cell, with · for padding spaces. bad combinations throw the same exceptions java throws; the formatter behind this figure was checked against String.format on jdk 25 for 31,616 combinations.

the ones you'll actually use:

specifiermeansexample → result
%dinteger42 → 42
%sanything, via toString()"duke" → duke
%f, %.2fdecimal, 6 or 2 places3.14159 → 3.141590, 3.14
%,dthousands separators1000000 → 1,000,000
%5d, %-5swidth 5, right / left aligned42 → ···42
%05dzero-padded42 → 00042
%xhexadecimal255 → ff
%na newline (the platform's)
%%a literal %
predict the output
java
IO.println(String.format("%5.1f|", 3.14159));

reading input

for simple programs, java 25's IO.readln reads one line and returns it, with an optional prompt:

Main.java
void main() {
    String name = IO.readln("name? ");
    int age = Integer.parseInt(IO.readln("age? "));
    IO.println("hi " + name + ", next year you'll be " + (age + 1));
}
terminal
$ java Main.java
name? duke
age? 30
hi duke, next year you'll be 31

it always returns a whole line as a String (or null when the input has ended), and you convert it yourself. that's the simplest model, and it dodges the trap below completely.

the classic tool is java.util.Scanner, which can read the next token (nextInt, nextDouble, next) or the next line (nextLine). mixing the two is where everyone gets bitten:

program =
Main.java
  1. 1var in = new Scanner(System.in);
  2. 2IO.print("age? ");
  3. 3int age = in.nextInt();
  4. 4IO.print("name? ");
  5. 5String name = in.nextLine();
  6. 6IO.println(age + " [" + name + "]");
input buffer
4↑2⏎duke⏎
returned·
stdout
·

you type 42, enter, duke, enter. it all lands in one buffer, and the scanner reads it with a cursor.

step 1/4
step through, then switch programs. the input is typed as 42 enter duke enter. the arrow is the scanner's cursor. both programs were run with exactly this input on jdk 25.

the fix is to pick one style. either read everything as lines and parse (Integer.parseInt(in.nextLine()), or just IO.readln), or read everything as tokens. if you must mix, call an extra in.nextLine() after nextInt() to eat the leftover newline. and if the user types abc where you called nextInt(), you get InputMismatchException, so real programs read a line and validate it.

one level deeper:when Scanner is too slow+

Scanner parses with regular expressions, which is fine for a person typing, and painfully slow for a million lines of input (competitive programming, big files). the fast path is a BufferedReader over System.in: new BufferedReader(new InputStreamReader(System.in)), then readLine() in a loop and parse the pieces yourself. output has the same issue in reverse: System.out flushes on every newline, so printing a million lines one println at a time is slow. build the output in a StringBuilder (or wrap System.out in a PrintWriter with a buffer) and print it once. more in i/o streams.

keylines
  • three pipes: System.in, System.out, System.err. java 25's IO prints and reads through the same ones.
  • printf / String.format: %[flags][width][.precision]conversion. checked at run time, not compile time.
  • width is a minimum, precision is digits after the point (or max characters for %s).
  • IO.readln reads a whole line. simplest, and no surprises.
  • nextInt() leaves the newline behind. don't mix it with nextLine() without eating it.