University College of Applied SciencesProgramming 1
العربية
Lecture 4 · 100 min

The printf Method

How do we print text and numbers exactly the way we want?

Prepared by: Eng. Badereddin Mohammed Elhalimi · Eng. Mohammed Zuhair Kouhail

By the end of this lecture you will be able to

  1. Explain the parts of a printf line: the command, the template and the values
  2. Choose the right format specifier for each value
  3. Tell a compile error from a run-time error
  4. Control decimal places, width and alignment
  5. Print a neat table, and build formatted text with String.format
In this lecture
  1. printf works like a form with blanks
  2. Every printf line has three parts
  3. Five format specifiers cover the basics
  4. %t needs a suffix and a date value
  5. Each blank takes its value in order
  6. A wrong specifier passes the compiler and fails while running
  7. A compile error prevents running; a run-time error appears during it
  8. Missing values and mismatched specifiers also fail at run time
  9. %.2f sets the number of decimal places
  10. Width reserves columns: %5d aligns right and %-10s aligns left
  11. %05d, %c, %b and %% complete the toolbox
  12. Fixed widths print a table with straight columns
  13. String.format builds the formatted text without printing it
  14. Recap: printf = template + specifiers + values
  15. Review questions
Part one: the template and the values

printf works like a form with blanks

1. Template

The sentence with blanks. The sentence stays fixed, and each %s is an empty box waiting for a value.

"Hello %s!"
2. Value

What fills the blank.

"World"
3. Result

What you see on screen.

Hello World!

Fill the blank

Predict the output, then run. Change World to your name and run again.

public class Form {
    public static void main(String[] args) {
        System.out.printf("Hello %s!%n", "World");
    }
}
Output
Hello World!

Every printf line has three parts

PartIn the exampleMeaning
1. The commandSystem.out.printfPrint using the format I give you.
2. The template"Hello %s!%n"Fixed text with blanks to fill: %s and %n.
3. The values"World"What goes into the blanks, separated by commas.

We forgot %n on the first line. What does the program print?

public class NoNewLine {
    public static void main(String[] args) {
        System.out.printf("Hello %s!", "Sara");
        System.out.printf("Hello %s!%n", "Ali");
    }
}
Show the output
Output
Hello Sara!Hello Ali!

Why? printf prints only the template, so without %n the cursor stays on the same line. Press "Debug line by line" and watch where the output goes after each statement.

Five format specifiers cover the basics

SpecifierValueExampleOutputMemory trick
%sText (String)("%s", "Ali")Alis = string: text as it is
%dWhole number("%d", 25)25d = decimal: no decimal point
%fDecimal number("%f", 3.14)3.140000f = float: 6 decimals
%tDate and time("%tY", d)2026t = time, and Y means year
%nNew line("A%nB")A, Bn = new line: like pressing Enter

Try the specifiers

Predict each line. Then change the values, and add %n inside one of the texts to split it into two lines.

public class Specifiers {
    public static void main(String[] args) {
        System.out.printf("%s%n", "Ali");
        System.out.printf("%d%n", 25);
        System.out.printf("%f%n", 3.14);
        System.out.printf("A%nB%n");
    }
}
Output
Ali
25
3.140000
A
B

What does the d in %d mean?

%t needs a suffix and a date value

%t alone is not enough: the letter after it picks the part of the date, and Y means the year. The value itself must be a date, not an ordinary number.

Print the year

We use a fixed date so the output stays fixed. In GregorianCalendar, months count from 0, so 0 means January. Change the year to 2030 and run.

public class YearOnly {
    public static void main(String[] args) {
        System.out.printf("%tY%n", new java.util.GregorianCalendar(2026, 0, 1));
    }
}
Output
2026

Each blank takes its value in order

Two blanks, two values

Order matters: the 1st blank takes the 1st value, the 2nd takes the 2nd. Type matters: a number blank needs a number, and a text blank needs text.

public class NameAge {
    public static void main(String[] args) {
        System.out.printf("Name: %s, Age: %d%n", "Ali", 19);
    }
}
Output
Name: Ali, Age: 19

Quick check: what will be printed?

public class Blanks {
    public static void main(String[] args) {
        System.out.printf("%d + %d = %d", 2, 3, 5);
    }
}
Show the output
Output
2 + 3 = 5

Why? Each %d takes the next value in order: the 1st gets 2, the 2nd gets 3, the 3rd gets 5.

Quick check: which specifier fits the blank to print the price?

System.out.printf("Price: ___", 4.5);
Part two: when `printf` fails

A wrong specifier passes the compiler and fails while running

Quick check: spot the mistake. What happens when this line runs?

System.out.printf("Age: %d", "19");

Watch it fail

Run the program: Age: appears first, then the message java.util.IllegalFormatConversionException: d != java.lang.String. Then press "Debug line by line": compiling succeeds with no problem, and the failure happens at this line while it runs.

public class AgeError {
    public static void main(String[] args) {
        System.out.printf("Age: %d", "19");
        System.out.println("This line never runs");
    }
}
Output
Age: 
In the messageWhat it means
IllegalFormatConversionExceptionAn exception: the value does not fit the specifier.
dThe specifier: %d.
!=Does not fit.
java.lang.StringThe type of the value we gave: text.

A compile error prevents running; a run-time error appears during it

CompareCompile errorRun-time error
Who finds it?The compiler, javacThe JVM, while running
Does the program run?No, no .class file is producedYes, until it reaches the bad line
Any output?NothingWhatever printed before the error
Exampleint age = "19";printf("Age: %d", "19");

The same mistake, two different fates. In int age = "19"; the compiler knows the variable's type, so it rejects the line. But to the compiler, a printf template is just text, and any value after it is accepted.

This one is a compile error: the program never runs

Notice that Age: never appears here. Remove the quotation marks.

public class AgeCompile {
    public static void main(String[] args) {
        int age = "19";
        System.out.printf("Age: %d%n", age);
    }
}
Compiler messageincompatible types: String cannot be converted to int
Show the fix
public class AgeCompile {
    public static void main(String[] args) {
        int age = 19;
        System.out.printf("Age: %d%n", age);
    }
}
Output
Age: 19

Why? The compiler knows age is an int, so it stops before anything runs. That is why nothing prints.

This is a compile error too: the missing comma

The compiler does not read inside the template, but it does check the shape of the line. Add the comma between the template and the value.

public class AgeComma {
    public static void main(String[] args) {
        System.out.printf("Age: %d%n" 19);
    }
}
Compiler message')' expected
Show the fix
public class AgeComma {
    public static void main(String[] args) {
        System.out.printf("Age: %d%n", 19);
    }
}
Output
Age: 19

Why? The message looks unrelated to the cause: the compiler asks for ) because after the template it expects a comma or a closing parenthesis, and it found 19. The real cause is the missing comma.

Fix the run-time error

This program compiles but fails when it runs. Fix it to print Age: 19. There are two ways: remove the quotes around the value, or use %s.

public class AgeFix {
    public static void main(String[] args) {
        System.out.printf("Age: %d%n", "19");
    }
}
Expected output
Age: 19
Hint 1

"19" is text, and 19 is a number.

Solution
public class AgeFix {
    public static void main(String[] args) {
        System.out.printf("Age: %d%n", 19);
    }
}

Missing values and mismatched specifiers also fail at run time

The lineThe message after Exception in thread "main"Why
printf("%d", 4.5);IllegalFormatConversionException: d != java.lang.Double%d does not accept a decimal
printf("%f", 5);IllegalFormatConversionException: f != java.lang.Integer%f does not accept 5; write 5.0
printf("%s %d%n", "Ali");MissingFormatArgumentException: Format specifier '%d'Two blanks and one value
printf("%t", date);UnknownFormatConversionException: Conversion = 't'%t needs a suffix, like %tY

We swapped the two values. What appears in the output before the error?

public class Swapped {
    public static void main(String[] args) {
        System.out.printf("Name: %s, Age: %d%n", 19, "Ali");
    }
}
Show the output
Output
Name: 19, Age: 

Why? %s accepts any value, so it prints 19. Then %d reaches the text "Ali" and the program stops. That is why the start of the output can look fine while the mistake is elsewhere.

A missing value

Run the program and read the message, then add the value 19 after "Ali".

public class Missing {
    public static void main(String[] args) {
        System.out.printf("%s %d%n", "Ali");
    }
}
Output
Ali 
Part three: controlling the shape

%.2f sets the number of decimal places

%f always prints 6 decimal places, which we rarely want. The number after the dot sets the places, and the value is rounded for printing only; the variable itself does not change.

Change the number of places

Change %.2f to %.3f, then to %.0f, and predict the output each time.

public class Precision {
    public static void main(String[] args) {
        double pi = 3.14159;
        System.out.printf("%f%n", pi);
        System.out.printf("%.2f%n", pi);
        System.out.println(pi);
    }
}
Output
3.141590
3.14
3.14159

Does %.1f cut the digits or round them?

public class Rounding {
    public static void main(String[] args) {
        System.out.printf("%.1f%n", 2.75);
    }
}
Show the output
Output
2.8

Why? %.1f rounds to one place rather than cutting, so 2.75 becomes 2.8.

The receipt total

The price is 12.5 and the quantity is 3. Calculate the total in a double variable and print it with two decimal places, as in the expected output.

public class Receipt {
    public static void main(String[] args) {
        double price = 12.5;
        int quantity = 3;
        // Calculate the total and print it with printf

    }
}
Expected output
Total: 37.50
Hint 1

The template is "Total: %.2f%n".

Solution
public class Receipt {
    public static void main(String[] args) {
        double price = 12.5;
        int quantity = 3;
        double total = price * quantity;
        System.out.printf("Total: %.2f%n", total);
    }
}

Width reserves columns: %5d aligns right and %-10s aligns left

FormatMeaningValueOutput between |
%5d5 columns, aligned right42| 42|
%-5d5 columns, aligned left42|42 |
%-10s10 columns, aligned left"Ali"|Ali |
%8.2f8 columns, 2 of them decimals3.14159| 3.14|

The bars reveal the spaces

We put | around each value so you can see the spaces. Delete the - from %-10s: where did the name go?

public class Width {
    public static void main(String[] args) {
        System.out.printf("|%5d|%n", 42);
        System.out.printf("|%-10s|%n", "Ali");
        System.out.printf("|%8.2f|%n", 3.14159);
    }
}
Output
|   42|
|Ali       |
|    3.14|

The name is longer than the width. What happens?

public class TooLong {
    public static void main(String[] args) {
        System.out.printf("|%3s|%n", "Mohammed");
    }
}
Show the output
Output
|Mohammed|

Why? Width is a minimum, not a maximum: Java never cuts the value, it takes the columns it needs.

%05d, %c, %b and %% complete the toolbox

FormatValueOutputUse
%05d4200042Fills empty columns with zeros, like a student number
%c'A'AOne char
%btruetrueA boolean value
%%Needs no value%The percent sign itself

All four together

Change %05d to %07d, change passed to false, then run. Why does %% have no matching value?

public class Toolbox {
    public static void main(String[] args) {
        int id = 42;
        char grade = 'A';
        boolean passed = true;
        System.out.printf("ID: %05d%n", id);
        System.out.printf("Grade: %c%n", grade);
        System.out.printf("Passed: %b%n", passed);
        System.out.printf("Score: %d%%%n", 95);
    }
}
Output
ID: 00042
Grade: A
Passed: true
Score: 95%

How many % signs appear in the output?

public class Percent {
    public static void main(String[] args) {
        System.out.printf("Discount: 50%%%n");
    }
}
Show the output
Output
Discount: 50%

Why? %% prints one sign, and %n is a new line. A lone % at the end of the template fails at run time with UnknownFormatConversionException.

Fixed widths print a table with straight columns

The student table

The first line is the header, using the same widths as the rows below it. Press "Debug line by line" and watch the table build line by line. Then add a fourth student.

public class StudentTable {
    public static void main(String[] args) {
        System.out.printf("%-10s%5s%8s%n", "Name", "Age", "GPA");
        System.out.printf("%-10s%5d%8.2f%n", "Sara", 19, 3.75);
        System.out.printf("%-10s%5d%8.2f%n", "Ahmed", 20, 3.2);
        System.out.printf("%-10s%5d%8.2f%n", "Mohammed", 21, 2.5);
    }
}
Output
Name        Age     GPA
Sara         19    3.75
Ahmed        20    3.20
Mohammed     21    2.50

The price table

Print the expected table: the item name in width 8 aligned left, and the price in width 6 with two decimals. Book costs 12.5 and Pen costs 1.75.

public class PriceTable {
    public static void main(String[] args) {
        // Print the header, then one line for each item

    }
}
Expected output
Item     Price
Book     12.50
Pen       1.75
Hint 1

The header template is "%-8s%6s%n".

Hint 2

The row template is "%-8s%6.2f%n".

Solution
public class PriceTable {
    public static void main(String[] args) {
        System.out.printf("%-8s%6s%n", "Item", "Price");
        System.out.printf("%-8s%6.2f%n", "Book", 12.5);
        System.out.printf("%-8s%6.2f%n", "Pen", 1.75);
    }
}

String.format builds the formatted text without printing it

String.format uses the same template and values, but returns the text instead of printing it. We save it in a String variable and use it later.

Save the text, then print it

Press "Debug line by line". Nothing prints after the first line; instead, a line box appears holding the finished text, which we print twice without formatting it again.

public class FormatText {
    public static void main(String[] args) {
        String line = String.format("%s: %.2f", "GPA", 3.756);
        System.out.println(line);
        System.out.println(line);
    }
}
Output
GPA: 3.76
GPA: 3.76

Notice that the result of String.format is neither saved nor printed. What does the program print?

public class FormatOnly {
    public static void main(String[] args) {
        String.format("%05d", 42);
        System.out.println("Done");
    }
}
Show the output
Output
Done

Why? String.format only returns the text. If we do not use what it returns, it is lost. Printing is the job of printf and println.

The student code

Use String.format to build the code from the number 7, in 4 columns with leading zeros, and save it in the variable code. Then print Code: followed by its value using println.

public class StudentCode {
    public static void main(String[] args) {
        // Build the code with String.format, then print it

    }
}
Expected output
Code: 0007
Hint 1

%04d means 4 columns with leading zeros.

Solution
public class StudentCode {
    public static void main(String[] args) {
        String code = String.format("%04d", 7);
        System.out.println("Code: " + code);
    }
}

Recap: printf = template + specifiers + values

Template
"Hi %s%n"
Specifiers
%s %d %f %t %n
Values
"Sara"
Output
Hi Sara

Your turn

Print the name Sara and the age 19 on one line, as in the expected output, then move to a new line. Try it first, then use the hint. Once it passes, try it with your own name and age.

public class AboutMe {
    public static void main(String[] args) {
        // Print the sentence with printf

    }
}
Expected output
My name is Sara and I am 19.
Hint 1

The template is "My name is %s and I am %d.%n".

Solution
public class AboutMe {
    public static void main(String[] args) {
        System.out.printf("My name is %s and I am %d.%n", "Sara", 19);
    }
}

Review questions

What happens when System.out.printf("%f", 5); runs?

Which format prints a name aligned left in 12 columns?

Put it all together. What does the program print?

public class ReviewMix {
    public static void main(String[] args) {
        System.out.printf("%-6s|%03d|%.1f%%%n", "Sara", 7, 91.25);
    }
}
Show the output
Output
Sara  |007|91.3%

Why? %-6s takes 6 columns on the left, %03d fills with zeros, %.1f rounds to one place, and %% prints %.

What is the difference between printf and String.format?