Java Output (println)
Every Java program that talks to the outside world has to start somewhere, and for most beginners that starting point is printing text to the screen. Java gives you three closely related tools for this — System.out.println, System.out.print, and System.out.printf — and understanding exactly how each one behaves will save you from a long list of confusing bugs later on. This lesson covers all three in depth: what they are, how they work internally, and how to use them correctly.
Overview: How Output Works in Java
In Java, console output is handled through an object called System.out. System is a built-in class in the java.lang package (automatically available in every program, no import needed). It has a public static field named out, which is an instance of java.io.PrintStream. That PrintStream object is connected to the “standard output” stream of the operating system — normally your terminal or console window.
So when you write System.out.println("Hello"), you are really doing three things: accessing the System class, reading its static out field to get a PrintStream, and calling that stream’s println method. PrintStream defines many overloaded versions of println and print — one for each primitive type (int, double, boolean, char, etc.), one for String, and one for generic Object (which calls the object’s toString() method). The compiler picks the correct overload automatically based on the argument’s type, which is why you can print almost anything without converting it to a String yourself first.
The key difference between the two basic methods is simple: print writes its argument and stops, leaving the cursor on the same line. println writes its argument and then appends a line terminator, moving the cursor to a new line for whatever gets printed next. Internally, output is not always flushed to the terminal character by character — System.out is typically “auto-flushing” on newline, meaning it pushes buffered text out whenever a line terminator is written, which is one reason println feels more immediate than repeated print calls.
Syntax
System.out.println(argument);
System.out.print(argument);
System.out.printf(formatString, arguments...);
- System — the built-in class that represents the running Java system.
- out — a static field of type
PrintStreamconnected to standard output. - println(argument) — prints the argument, then moves to a new line. Calling it with no argument,
System.out.println(), prints just a blank line. - print(argument) — prints the argument with no trailing newline.
- printf(formatString, arguments…) — prints text built from a format string containing
%-conversions (like%d,%s,%f), substituting each conversion with the corresponding argument, in order. - argument — can be a
String, a number, achar, aboolean, or any object; Java converts it to text using the matching overload or, for objects, the object’stoString()method.
Examples
Example 1: print vs println
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
System.out.print("No newline here... ");
System.out.print("still same line.");
System.out.println();
System.out.println("Now on a new line.");
}
}
Output:
Hello, World!
No newline here... still same line.
Now on a new line.
The first println prints its text and moves to a new line. The two print calls both write to the same line because neither adds a newline — notice how their text runs together with no gap you didn’t type yourself. The empty System.out.println() call then inserts a line break by itself, pushing the final message onto its own line.
Example 2: Printing Variables and the Concatenation Gotcha
public class Main {
public static void main(String[] args) {
String name = "Ava";
int age = 29;
double score = 91.5;
boolean passed = true;
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.println("Score: " + score);
System.out.println("Passed: " + passed);
System.out.println("Next year age: " + (age + 1));
System.out.println("Concatenation gotcha: " + age + 1);
}
}
Output:
Name: Ava
Age: 29
Score: 91.5
Passed: true
Next year age: 30
Concatenation gotcha: 291
Java’s + operator is overloaded: between two numbers it adds them, but if either side is a String, it concatenates text instead. "Next year age: " + (age + 1) works as expected because the parentheses force age + 1 to be evaluated as arithmetic first, producing 30, which is then converted to text and appended. But "Concatenation gotcha: " + age + 1 is evaluated left to right: "Concatenation gotcha: " + age becomes the string "Concatenation gotcha: 29", and then + 1 appends the character 1 rather than adding numerically, giving "...29" + "1" which is 291. This is one of the most common beginner surprises in Java output.
Example 3: Formatted Output with printf
public class Main {
public static void main(String[] args) {
String product = "Widget";
double price = 19.999;
int quantity = 3;
System.out.printf("Product: %s%n", product);
System.out.printf("Price: $%.2f%n", price);
System.out.printf("Quantity: %d%n", quantity);
System.out.printf("%-10s | %8s%n", "Item", "Total");
System.out.printf("%-10s | %8.2f%n", product, price * quantity);
}
}
Output:
Product: Widget
Price: $20.00
Quantity: 3
Item | Total
Widget | 60.00
printf uses a format string with %-conversions: %s for strings, %d for integers, and %.2f for a floating-point number rounded to two decimal places (note 19.999 rounds up to 20.00, and 19.999 * 3 = 59.997 rounds to 60.00). The %n conversion inserts a platform-correct newline, which is safer than hardcoding \n in cross-platform code. The -10 and 8 numbers are field widths: %-10s left-justifies text in a 10-character-wide column, while %8s and %8.2f right-justify within an 8-character column, which is how the two rows line up into neat columns.
Under the Hood
When a Java program runs, the JVM (Java Virtual Machine) initializes the System class very early, before your main method even starts, setting up System.out, System.err, and System.in as the standard output, error, and input streams inherited from the operating system process. System.out specifically is wrapped in a PrintStream, which itself wraps a lower-level byte stream connected to the console (or, if you redirect output with something like > in the shell, to a file).
Each call to println or print converts its argument to a sequence of characters (using String.valueOf() internally for primitives, or the argument’s own toString() for objects), encodes those characters into bytes using the platform’s default character encoding, and writes those bytes to the underlying output stream. Because PrintStream methods never throw checked exceptions (any I/O error just sets an internal error flag you can check with checkError()), you can chain calls to println freely without wrapping them in try-catch blocks, which is part of why output is so easy to use for beginners.
Common Mistakes
Mistake 1: Expecting print to add a newline.
System.out.print("Loading");
System.out.print("Done");
This prints LoadingDone on one line, which surprises beginners who assume every output statement starts a fresh line. Fix it by switching to println, or by manually adding "\n" or a space where you want separation:
System.out.println("Loading");
System.out.println("Done");
Mistake 2: Assuming + always adds numbers.
int a = 5, b = 10;
System.out.println("Sum: " + a + b); // prints "Sum: 510", not 15
As shown earlier, mixing strings and numbers with + is evaluated left to right. Fix it with parentheses so the arithmetic happens first:
System.out.println("Sum: " + (a + b)); // prints "Sum: 15"
Best Practices
- Use
printlnfor normal line-based output andprintonly when you specifically need to continue on the same line (like building a row of characters in a loop). - Use
printf(orString.format) whenever you need aligned columns, fixed decimal places, or padded numbers — string concatenation for this quickly becomes unreadable. - Always wrap mixed arithmetic-and-concatenation expressions in parentheses to avoid the left-to-right
+gotcha. - Prefer
%nover a literal\ninsideprintfformat strings for portability across operating systems. - Reserve
System.err.printlnfor error and diagnostic messages so they’re logically separate from normal program output, even though both usually appear in the same terminal. - Avoid overusing
printlnas a permanent debugging tool in larger programs — for anything beyond a small script, a proper logging framework gives you more control (timestamps, levels, filtering).
Practice Exercises
Exercise 1: Write a program that declares three variables — your name (String), your age (int), and your city (String) — and prints them as a single sentence on one line using string concatenation.
Exercise 2: Write a program with two integers, x = 7 and y = 3, that prints “x + y = 10” using string concatenation with correct parenthesization. Then print a second line showing the same calculation done incorrectly (without parentheses) so you can see the difference in output.
Exercise 3: Using printf, print a small receipt with three items, each with a name and a price, aligned so that all the item names are left-justified in a 12-character column and all the prices are right-justified with two decimal places in an 8-character column.
Summary
System.outis aPrintStreamfield on the built-inSystemclass, connected to the standard output stream.printlnprints its argument and then moves to a new line;printprints without a newline.printfbuilds formatted text from a format string with%-conversions like%s,%d, and%.2f, and supports field widths and alignment.- The
+operator concatenates when either operand is aString, and evaluates left to right — parenthesize arithmetic to avoid surprising output. %nis the safer, platform-independent way to insert a newline insideprintfformat strings.- Output methods on
PrintStreamnever throw checked exceptions, which is why you can call them freely without try-catch.
