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.
printing
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"));
}hi duke no newline, then one duke bought 3 items for $1,234.50 left | right|
| method | does |
|---|---|
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.
· 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:
| specifier | means | example → result |
|---|---|---|
%d | integer | 42 → 42 |
%s | anything, via toString() | "duke" → duke |
%f, %.2f | decimal, 6 or 2 places | 3.14159 → 3.141590, 3.14 |
%,d | thousands separators | 1000000 → 1,000,000 |
%5d, %-5s | width 5, right / left aligned | 42 → ···42 |
%05d | zero-padded | 42 → 00042 |
%x | hexadecimal | 255 → ff |
%n | a newline (the platform's) | |
%% | a literal % |
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:
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));
}$ java Main.java
name? duke
age? 30
hi duke, next year you'll be 31it 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:
- 1var in = new Scanner(System.in);
- 2IO.print("age? ");
- 3int age = in.nextInt();
- 4IO.print("name? ");
- 5String name = in.nextLine();
- 6IO.println(age + " [" + name + "]");
you type 42, enter, duke, enter. it all lands in one buffer, and the scanner reads it with a cursor.
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.
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.
- three pipes: System.in, System.out, System.err. java 25's
IOprints 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.readlnreads a whole line. simplest, and no surprises.nextInt()leaves the newline behind. don't mix it withnextLine()without eating it.