- Learn printf() and String.format() for formatted output
- Master format specifiers, flags, width, and precision
- Create professional-looking console output and reports
Formatted Output in Java
You know how System.out.println() just dumps everything on a new line? Sometimes you need more control. Maybe you're printing a price and want exactly two decimal places, or you're creating a table where columns need to line up perfectly. That's where printf() comes in.
printf() - Your Formatting Tool
Think of printf() as println() with superpowers. Instead of just printing whatever you give it, you create a template with placeholders, then fill in the values:
public class BasicPrintf {
public static void main(String[] args) {
String name = "Alice";
int age = 25;
double height = 5.6;
System.out.printf("Name: %s%n", name);
System.out.printf("Age: %d years%n", age);
System.out.printf("Height: %.1f feet%n", height);
// Or all at once
System.out.printf("Name: %s, Age: %d, Height: %.1f%n", name, age, height);
}
}
See those %s, %d, and %.1f? Those are format specifiers - placeholders that tell Java what type of value to expect and how to display it.
The Common Specifiers
| Specifier | Type | Example | Output |
|---|---|---|---|
%s |
String | printf("%s", "hello") |
hello |
%d |
Integer | printf("%d", 42) |
42 |
%f |
Float/Double | printf("%f", 3.14) |
3.140000 |
%c |
Character | printf("%c", 'A') |
A |
%b |
Boolean | printf("%b", true) |
true |
%n |
Newline | printf("Hello%n") |
Hello (with newline) |
Quick note: Use %n instead of \n for newlines. It automatically uses the right line ending for your operating system.
Controlling Width and Precision
Here's where it gets useful. Say you're printing prices - sometimes they're $9.99, sometimes $1234.56. Without formatting, your output looks messy. With precision control, you decide exactly how many decimal places to show:
public class WidthPrecision {
public static void main(String[] args) {
// Width: reserve space for the number
System.out.printf("Number: %5d%n", 42); // " 42" (right-aligned in 5 spaces)
System.out.printf("Number: %-5d%n", 42); // "42 " (left-aligned)
// Precision: control decimal places
System.out.printf("Pi: %.2f%n", Math.PI); // 3.14
System.out.printf("Pi: %.4f%n", Math.PI); // 3.1416
// Combine them for perfect price formatting
System.out.printf("Price: $%8.2f%n", 29.99); // "$ 29.99"
System.out.printf("Price: $%8.2f%n", 1234.56); // "$1234.56"
}
}
The number before the decimal is the total width (including the decimal point), and the number after is how many decimal places.
Formatting Flags
Flags are little modifiers that change how your output looks:
| Flag | Description | Example | Output |
|---|---|---|---|
- |
Left-align | %-10s |
Left-aligned in 10 spaces |
+ |
Show positive sign | %+d |
+42 |
|
Space for positive | % d |
42 |
0 |
Zero-pad | %05d |
00042 |
, |
Use grouping separator | %,d |
1,234 |
public class FormattingFlags {
public static void main(String[] args) {
// Alignment matters when you're creating columns
System.out.printf("Left: %-10s Right: %10s%n", "Hello", "World");
// Show signs for positive/negative numbers
System.out.printf("Positive: %+d, Negative: %+d%n", 42, -42);
// Zero padding is great for IDs or codes
System.out.printf("Order ID: %05d%n", 42); // "Order ID: 00042"
// Commas make big numbers readable
System.out.printf("Population: %,d%n", 1234567); // "1,234,567"
// Put it together for currency
System.out.printf("Revenue: $%,.2f%n", 1234567.89); // "$1,234,567.89"
}
}
String.format() - Same Thing, Different Use
String.format() works exactly like printf(), but instead of printing immediately, it returns a formatted string you can use later:
public class StringFormat {
public static void main(String[] args) {
String name = "Bob";
int score = 95;
// Build the string first, print later
String message = String.format("Student %s scored %d%%", name, score);
System.out.println(message);
// Handy for creating filenames
String filename = String.format("report_%s_%tY-%tm-%td.txt",
name,
new java.util.Date(),
new java.util.Date(),
new java.util.Date());
System.out.println("Filename: " + filename);
}
}
This is particularly useful when you need to build a string to pass to another method, or when you're constructing error messages.
Dates and Times
Date formatting has its own set of specifiers (they all start with %t):
import java.util.Date;
public class DateFormatting {
public static void main(String[] args) {
Date now = new Date();
System.out.printf("Current date: %tF%n", now); // 2023-11-21
System.out.printf("Current time: %tT%n", now); // 14:30:25
System.out.printf("Date and time: %tc%n", now); // Full: Wed Nov 21 14:30:25 EST 2023
// Build your own format
System.out.printf("Custom: %tY-%tm-%td %tH:%tM:%tS%n",
now, now, now, now, now, now);
}
}
Notice how you have to pass now multiple times? Each %t needs its own argument. A bit annoying, but that's how it works.
Other Number Formats
Sometimes you need hexadecimal or scientific notation:
public class NumberFormatting {
public static void main(String[] args) {
double value = 12345.6789;
System.out.printf("Scientific: %e%n", value); // 1.234568e+04
System.out.printf("Hex: %x%n", 255); // ff
System.out.printf("Hex uppercase: %X%n", 255); // FF
System.out.printf("Octal: %o%n", 64); // 100
}
}
Practical Examples
Let's look at situations where formatting actually matters.
Creating aligned tables:
public class TableFormat {
public static void main(String[] args) {
String[] names = {"Alice", "Bob", "Charlie"};
int[] ages = {25, 30, 35};
double[] salaries = {50000, 60000, 70000};
System.out.printf("%-10s %-5s %-10s%n", "Name", "Age", "Salary");
System.out.println("-".repeat(25));
for (int i = 0; i < names.length; i++) {
System.out.printf("%-10s %-5d $%-10.2f%n",
names[i], ages[i], salaries[i]);
}
}
}
Output looks like:
Name Age Salary
-------------------------
Alice 25 $50000.00
Bob 30 $60000.00
Charlie 35 $70000.00
See how everything lines up? Without formatting, it'd be a mess.
Building reports:
public class ReportFormat {
public static void main(String[] args) {
String title = "Monthly Sales Report";
String date = "November 2023";
double sales = 125000.50;
double target = 150000.00;
System.out.println("=".repeat(50));
System.out.printf("%30s%n", title); // Center-ish
System.out.printf("%30s%n", date);
System.out.println("=".repeat(50));
System.out.printf("%-20s $%,15.2f%n", "Total Sales:", sales);
System.out.printf("%-20s $%,15.2f%n", "Sales Target:", target);
System.out.printf("%-20s %15.1f%%%n", "Achievement:",
(sales / target) * 100);
System.out.println("=".repeat(50));
}
}
A Few Tips
Watch out for nulls. If you pass null where printf expects a value, you'll get "null" in your output (or possibly an exception). Better to check first:
String name = null;
System.out.printf("Name: %s%n", name != null ? name : "Unknown");
Reuse format strings. If you're printing the same format over and over, save it as a constant:
private static final String ROW_FORMAT = "%-20s | $%10.2f | %-15s%n";
System.out.printf(ROW_FORMAT, "John Doe", 75000.50, "Engineering");
System.out.printf(ROW_FORMAT, "Jane Smith", 82000.75, "Marketing");
Be mindful of locales. Number formatting can vary by country:
import java.util.Locale;
public class InternationalFormatting {
public static void main(String[] args) {
double price = 1234.56;
System.out.printf(Locale.US, "US Price: $%,.2f%n", price);
// US Price: $1,234.56
System.out.printf(Locale.GERMANY, "German Price: %, .2f €%n", price);
// German Price: 1.234,56 € (note the reversed comma/period)
System.out.printf(Locale.FRANCE, "French Price: %, .2f €%n", price);
// French Price: 1 234,56 €
}
}
Different countries use different decimal separators and thousands separators. If your app needs to work internationally, you might need to handle this.
When to Use Formatting
Use printf() when you need precise control over output layout - tables, reports, aligned columns, or specific decimal places. For simple output where appearance doesn't matter much, regular println() is fine. The extra syntax only pays off when clean formatting actually matters to whoever's reading the output.
