Java String Formatting
Java String Formatting
Writing "Total: Rs." + amount + " for " + qty + " items on " + date works — but it becomes harder to read with every added field. String formatting gives you a template with labelled placeholders and fills them in cleanly. String.format("Total: Rs.%.2f for %d items on %s", amount, qty, date) reads like a sentence with blanks to fill, not a chain of plus signs and string fragments.
Java offers several ways to format strings: String.format() for creating formatted String objects, System.out.printf() for formatted console output, and Formatter for advanced formatting to any output target. All three use the same format specifier syntax — learn it once, use it everywhere.
Format Specifiers — The Building Blocks
A format specifier is a placeholder in a format string that gets replaced with a value. Every specifier starts with % and ends with a conversion character.
Anatomy of a format specifier: % [argument index$] [flags] [width] [.precision] conversion Examples: %s → String %d → Integer (decimal) %f → Floating-point %.2f → Floating-point, 2 decimal places %10s → String, right-aligned in 10 characters %-10s → String, left-aligned in 10 characters %05d → Integer, padded with zeros to width 5 %,d → Integer with thousand separators %n → Platform-specific newline %% → Literal % character Common conversion characters: s / S → String (S = uppercase) d → Decimal integer f → Floating-point e / E → Scientific notation b / B → Boolean c / C → Character x / X → Hexadecimal integer o → Octal integer n → Newline % → Literal percent sign
1 — String.format() — Creating Formatted Strings
String.format(template, args...) returns a formatted String without printing it. This is the most common formatting method in production code — used for building messages, log entries, API responses, report lines, and display values.
1// File: StringFormatBasics.java
2
3public class StringFormatBasics {
4
5 public static void main(String[] args) {
6
7 // String specifier — %s
8 String name = "Priya Sharma";
9 String role = "Senior Developer";
10 String result = String.format("Name: %s | Role: %s", name, role);
11 System.out.println(result);
12
13 // Integer specifier — %d
14 int orderId = 2024001;
15 int qty = 3;
16 System.out.println(String.format("Order #%d — Qty: %d", orderId, qty));
17
18 // Float specifier — %f and %.2f
19 double price = 1299.999;
20 System.out.println(String.format("Price: %f", price)); // 6 decimal places default
21 System.out.println(String.format("Price: %.2f", price)); // exactly 2 decimal places
22 System.out.println(String.format("Price: %.0f", price)); // rounded, no decimal
23
24 System.out.println();
25
26 // Boolean specifier — %b
27 boolean isActive = true;
28 System.out.println(String.format("Account active: %b", isActive));
29
30 // Character specifier — %c
31 char grade = 'A';
32 System.out.println(String.format("Grade: %c", grade));
33
34 // Hexadecimal — %x and %X
35 int colorCode = 16711680; // red in decimal
36 System.out.println(String.format("Color hex: #%X", colorCode)); // FF0000
37
38 System.out.println();
39
40 // Multiple values in one format string
41 String orderId2 = "ORD-2024-88291";
42 String customer = "Rohan Mehta";
43 double amount = 4999.50;
44 String status = "PLACED";
45 System.out.println(String.format(
46 "Order: %-20s | Customer: %-15s | Amount: Rs.%8.2f | Status: %s",
47 orderId2, customer, amount, status));
48 }
49}Output:
Name: Priya Sharma | Role: Senior Developer
Order #2024001 — Qty: 3
Price: 1300.000000
Price: 1300.00
Price: 1300
Account active: true
Grade: A
Color hex: #FF0000
Order: ORD-2024-88291 | Customer: Rohan Mehta | Amount: Rs. 4999.50 | Status: PLACED
2 — Width and Alignment
Width controls the minimum number of characters a value occupies. Left-align with -, right-align (default), and pad with zeros using 0 flag.
1// File: WidthAlignmentDemo.java
2
3public class WidthAlignmentDemo {
4
5 public static void main(String[] args) {
6
7 // Right-aligned (default)
8 System.out.println(String.format("'%10s'", "Java")); // ' Java'
9 System.out.println(String.format("'%10d'", 42)); // ' 42'
10 System.out.println(String.format("'%10.2f'", 3.14)); // ' 3.14'
11
12 // Left-aligned — add - flag
13 System.out.println(String.format("'%-10s'", "Java")); // 'Java '
14 System.out.println(String.format("'%-10d'", 42)); // '42 '
15 System.out.println(String.format("'%-10.2f'", 3.14)); // '3.14 '
16
17 // Zero-padding — add 0 flag
18 System.out.println(String.format("'%010d'", 42)); // '0000000042'
19 System.out.println(String.format("'%010.2f'", 3.14)); // '0000003.14'
20
21 System.out.println();
22
23 // Building an aligned table
24 System.out.println(String.format("%-5s %-20s %10s %8s", "Sr.", "Product", "Price", "Stock"));
25 System.out.println("-".repeat(47));
26
27 Object[][] products = {
28 {1, "Wireless Headphones", "Rs.2,499", 150},
29 {2, "USB-C Hub", "Rs.899", 280},
30 {3, "Mechanical Keyboard", "Rs.3,999", 80},
31 {4, "Laptop Stand", "Rs.1,299", 200},
32 };
33
34 for (Object[] p : products) {
35 System.out.println(String.format("%-5d %-20s %10s %8d",
36 p[0], p[1], p[2], p[3]));
37 }
38 }
39}Output:
' Java'
' 42'
' 3.14'
'Java '
'42 '
'3.14 '
'0000000042'
'0000003.14'
Sr. Product Price Stock
-----------------------------------------------
1 Wireless Headphones Rs.2,499 150
2 USB-C Hub Rs.899 280
3 Mechanical Keyboard Rs.3,999 80
4 Laptop Stand Rs.1,299 200
3 — Number Formatting
Numbers have special flags for thousand separators, sign display, and scientific notation.
1// File: NumberFormattingDemo.java
2
3import java.util.Locale;
4
5public class NumberFormattingDemo {
6
7 public static void main(String[] args) {
8
9 double salary = 125000.75;
10 double bigNumber = 98765432.10;
11 int population = 1400000000;
12 double pi = Math.PI;
13 double tiny = 0.000001234;
14
15 // Thousand separators — , flag
16 System.out.println(String.format("Salary : Rs.%,.2f", salary));
17 System.out.println(String.format("Revenue : Rs.%,.0f", bigNumber));
18 System.out.println(String.format("Population : %,d", population));
19
20 System.out.println();
21
22 // Precision control
23 System.out.println(String.format("Pi (2dp) : %.2f", pi));
24 System.out.println(String.format("Pi (5dp) : %.5f", pi));
25 System.out.println(String.format("Pi (10dp) : %.10f", pi));
26
27 System.out.println();
28
29 // Scientific notation — %e
30 System.out.println(String.format("Tiny %%e : %e", tiny));
31 System.out.println(String.format("Tiny %%.2e : %.2e", tiny));
32 System.out.println(String.format("Big %%E : %E", bigNumber));
33
34 System.out.println();
35
36 // Sign display — + flag (always show sign)
37 System.out.println(String.format("Positive: %+.2f", 99.5));
38 System.out.println(String.format("Negative: %+.2f", -45.0));
39
40 System.out.println();
41
42 // Leading space for positive (aligns with negative)
43 System.out.println(String.format("Profit: % .2f", 12500.0));
44 System.out.println(String.format("Loss : % .2f", -3200.0));
45
46 System.out.println();
47
48 // Locale-specific formatting (comma vs dot as decimal separator)
49 System.out.println(String.format(Locale.US, "US format : %,.2f", salary));
50 System.out.println(String.format(Locale.GERMAN, "German format: %,.2f", salary));
51 System.out.println(String.format(Locale.FRENCH, "French format: %,.2f", salary));
52 }
53}Output:
Salary : Rs.1,25,000.75
Revenue : Rs.9,87,65,432
Population : 1,400,000,000
Pi (2dp) : 3.14
Pi (5dp) : 3.14159
Pi (10dp) : 3.1415926536
Tiny %e : 1.234000e-06
Tiny %.2e : 1.23e-06
Big %E : 9.876543E+07
Positive: +99.50
Negative: -45.00
Profit: 12500.00
Loss : -3200.00
US format : 125,000.75
German format: 125.000,75
French format: 125 000,75
The , flag in Indian locale produces Indian numbering (lakhs and crores). For proper Indian currency formatting, use Locale with NumberFormat or control grouping manually.
4 — printf() — Formatted Console Output
System.out.printf() is identical to System.out.print(String.format(...)) — it formats and prints directly without creating an intermediate String variable.
1// File: PrintfDemo.java
2
3public class PrintfDemo {
4
5 public static void main(String[] args) {
6
7 // printf — formats and prints directly
8 System.out.printf("Name: %s%n", "Sneha Rao"); // %n = newline
9 System.out.printf("Score: %d / %d%n", 87, 100);
10 System.out.printf("Average: %.2f%n", 87.0 / 100.0);
11
12 System.out.println();
13
14 // Build a receipt using printf
15 System.out.printf("%-30s%n", "RECEIPT — ZOMATO ORDER");
16 System.out.printf("%-30s%n", "-".repeat(30));
17 System.out.printf("%-22s %7s%n", "Item", "Price");
18 System.out.printf("%-30s%n", "-".repeat(30));
19
20 String[][] items = {
21 {"Chicken Biryani", "Rs.349"},
22 {"Garlic Naan x2", "Rs.120"},
23 {"Raita", "Rs.49"},
24 {"Mango Lassi", "Rs.89"},
25 };
26
27 for (String[] item : items) {
28 System.out.printf("%-22s %7s%n", item[0], item[1]);
29 }
30
31 System.out.printf("%-30s%n", "-".repeat(30));
32 System.out.printf("%-22s %7s%n", "TOTAL", "Rs.607");
33 System.out.printf("%-22s %7s%n", "Delivery Charge", "Rs.30");
34 System.out.printf("%-30s%n", "-".repeat(30));
35 System.out.printf("%-22s %7s%n", "GRAND TOTAL", "Rs.637");
36 }
37}Output:
Name: Sneha Rao
Score: 87 / 100
Average: 0.87
RECEIPT — ZOMATO ORDER
------------------------------
Item Price
------------------------------
Chicken Biryani Rs.349
Garlic Naan x2 Rs.120
Raita Rs.49
Mango Lassi Rs.89
------------------------------
TOTAL Rs.607
Delivery Charge Rs.30
------------------------------
GRAND TOTAL Rs.637
5 — Argument Index — Reusing Arguments
The argument index %n$ lets you reference the same argument multiple times without repeating it in the argument list.
1// File: ArgumentIndexDemo.java
2
3public class ArgumentIndexDemo {
4
5 public static void main(String[] args) {
6
7 // Without argument index — normal left-to-right
8 System.out.println(String.format("%s bought %d items for Rs.%,.2f",
9 "Priya", 3, 1299.0));
10
11 // With argument index — reference arguments by position (1-based)
12 System.out.println(String.format(
13 "Order by %1$s. %1$s's total: Rs.%2$.2f. %1$s will receive a receipt.",
14 "Priya", 1299.0));
15 // %1$ refers to arg 1 ("Priya") — used three times
16 // %2$ refers to arg 2 (1299.0)
17
18 System.out.println();
19
20 // Practical use — multilingual templates where order varies
21 String template = "Dear %1$s, your order %2$s worth Rs.%3$.2f is confirmed.";
22 System.out.println(String.format(template, "Rohan", "ORD-001", 2499.0));
23 System.out.println(String.format(template, "Sneha", "ORD-002", 899.0));
24 }
25}Output:
Priya bought 3 items for Rs.1,299.00
Order by Priya. Priya's total: Rs.1299.00. Priya will receive a receipt.
Dear Rohan, your order ORD-001 worth Rs.2499.00 is confirmed.
Dear Sneha, your order ORD-002 worth Rs.899.00 is confirmed.
6 — Formatted() — Java 15+
Java 15 introduced String.formatted() as an instance method — an alternative to String.format() that reads more naturally when the template is a variable.
1// File: FormattedMethodDemo.java
2
3public class FormattedMethodDemo {
4
5 public static void main(String[] args) {
6
7 // Traditional String.format()
8 String msg1 = String.format("Hello, %s! Your score is %d.", "Karan", 92);
9 System.out.println(msg1);
10
11 // Java 15+ String.formatted() — same result, different syntax
12 String msg2 = "Hello, %s! Your score is %d.".formatted("Karan", 92);
13 System.out.println(msg2);
14
15 System.out.println();
16
17 // Particularly clean with text blocks (Java 15+)
18 String template = """
19 Dear %s,
20 Your order %s has been placed successfully.
21 Total amount: Rs.%.2f
22 Expected delivery: %s
23 """;
24
25 String email = template.formatted(
26 "Ananya Iyer",
27 "ORD-2024-99812",
28 3499.50,
29 "Jan 18, 2024"
30 );
31
32 System.out.println(email);
33 }
34}Output:
Hello, Karan! Your score is 92.
Hello, Karan! Your score is 92.
Dear Ananya Iyer,
Your order ORD-2024-99812 has been placed successfully.
Total amount: Rs.3499.50
Expected delivery: Jan 18, 2024
Format Specifiers — Complete Quick Reference Table
| Specifier | Type | Example | Output |
|---|---|---|---|
%s | String | "Hello %s".formatted("World") | Hello World |
%S | String uppercase | "%S".formatted("java") | JAVA |
%d | Decimal int | "%d".formatted(42) | 42 |
%05d | Zero-padded int | "%05d".formatted(42) | 00042 |
%,d | Int with separator | "%,d".formatted(1000000) | 1,000,000 |
%f | Float (6dp) | "%f".formatted(3.14) | 3.140000 |
%.2f | Float (2dp) | "%.2f".formatted(3.14159) | 3.14 |
%,.2f | Float + separator | "%,.2f".formatted(99999.9) | 99,999.90 |
%e | Scientific | "%e".formatted(12345.6) | 1.234560e+04 |
%10s | Right-aligned | "%10s".formatted("hi") | __________hi (8 spaces) |
%-10s | Left-aligned | "%-10s".formatted("hi") | hi__________ (8 spaces) |
%b | Boolean | "%b".formatted(true) | true |
%c | Character | "%c".formatted('A') | A |
%x | Hex lowercase | "%x".formatted(255) | ff |
%X | Hex uppercase | "%X".formatted(255) | FF |
%n | Newline | "Line1%nLine2" | Two lines |
%% | Literal % | "100%%" | 100% |
%+.2f | Always show sign | "%+.2f".formatted(5.0) | +5.00 |
Real-World Example — Bank Statement Generator
The Business Problem
A digital banking app like CRED or a neobank generates monthly statements with transaction records. Each row must be consistently formatted — date left-aligned, description padded for readability, amounts right-aligned with two decimals, and running balance shown. The header and footer must match the column widths exactly. String formatting makes this clean and maintainable.
1// File: Transaction.java
2
3public class Transaction {
4 private final String date;
5 private final String description;
6 private final String type; // CREDIT or DEBIT
7 private final double amount;
8
9 public Transaction(String date, String description,
10 String type, double amount) {
11 this.date = date;
12 this.description = description;
13 this.type = type;
14 this.amount = amount;
15 }
16
17 public String getDate() { return date; }
18 public String getDescription() { return description; }
19 public String getType() { return type; }
20 public double getAmount() { return amount; }
21 public boolean isCredit() { return "CREDIT".equals(type); }
22}1// File: StatementGenerator.java
2
3import java.util.List;
4
5public class StatementGenerator {
6
7 private static final int DATE_W = 12;
8 private static final int DESC_W = 28;
9 private static final int TYPE_W = 8;
10 private static final int AMT_W = 12;
11 private static final int BAL_W = 14;
12 private static final int TOTAL_W = DATE_W + DESC_W + TYPE_W + AMT_W + BAL_W + 4;
13
14 public static String generate(String accountHolder,
15 String accountNumber,
16 String period,
17 double openingBalance,
18 List<Transaction> transactions) {
19
20 StringBuilder sb = new StringBuilder(2048);
21
22 // Header
23 sb.append("=".repeat(TOTAL_W)).append("\n");
24 sb.append(String.format(" ACCOUNT STATEMENT — %s%n", accountHolder.toUpperCase()));
25 sb.append(String.format(" Account : %s Period: %s%n", accountNumber, period));
26 sb.append("=".repeat(TOTAL_W)).append("\n");
27
28 // Column headers
29 sb.append(String.format("%-" + DATE_W + "s %-" + DESC_W + "s %-" + TYPE_W
30 + "s %" + AMT_W + "s %" + BAL_W + "s%n",
31 "Date", "Description", "Type", "Amount (Rs.)", "Balance (Rs.)"));
32 sb.append("-".repeat(TOTAL_W)).append("\n");
33
34 // Transaction rows
35 double balance = openingBalance;
36 double totalCredit = 0;
37 double totalDebit = 0;
38
39 for (Transaction txn : transactions) {
40 if (txn.isCredit()) {
41 balance += txn.getAmount();
42 totalCredit += txn.getAmount();
43 } else {
44 balance -= txn.getAmount();
45 totalDebit += txn.getAmount();
46 }
47
48 String amountStr = String.format("%s%,.2f",
49 txn.isCredit() ? "+" : "-", txn.getAmount());
50
51 sb.append(String.format("%-" + DATE_W + "s %-" + DESC_W + "s %-" + TYPE_W
52 + "s %" + AMT_W + "s %" + BAL_W + ".2f%n",
53 txn.getDate(),
54 txn.getDescription(),
55 txn.getType(),
56 amountStr,
57 balance));
58 }
59
60 // Summary footer
61 sb.append("=".repeat(TOTAL_W)).append("\n");
62 sb.append(String.format("%-" + (DATE_W + DESC_W + TYPE_W + 2) + "s %" + AMT_W
63 + "s %" + BAL_W + ".2f%n",
64 "Opening Balance",
65 "",
66 openingBalance));
67 sb.append(String.format("%-" + (DATE_W + DESC_W + TYPE_W + 2) + "s %" + AMT_W
68 + ".2f %" + BAL_W + "s%n",
69 "Total Credits",
70 totalCredit, ""));
71 sb.append(String.format("%-" + (DATE_W + DESC_W + TYPE_W + 2) + "s %" + AMT_W
72 + ".2f %" + BAL_W + "s%n",
73 "Total Debits",
74 totalDebit, ""));
75 sb.append("-".repeat(TOTAL_W)).append("\n");
76 sb.append(String.format("%-" + (DATE_W + DESC_W + TYPE_W + 2) + "s %" + AMT_W
77 + "s %" + BAL_W + ".2f%n",
78 "Closing Balance",
79 "",
80 balance));
81 sb.append("=".repeat(TOTAL_W)).append("\n");
82
83 return sb.toString();
84 }
85}1// File: StatementDemo.java
2
3import java.util.List;
4
5public class StatementDemo {
6
7 public static void main(String[] args) {
8
9 List<Transaction> transactions = List.of(
10 new Transaction("01-Jan-2024", "Opening Credit", "CREDIT", 50000.00),
11 new Transaction("03-Jan-2024", "Swiggy Food Order", "DEBIT", 649.00),
12 new Transaction("05-Jan-2024", "Salary Jan 2024", "CREDIT", 85000.00),
13 new Transaction("08-Jan-2024", "EMI - Home Loan", "DEBIT", 22000.00),
14 new Transaction("10-Jan-2024", "Amazon Shopping", "DEBIT", 3499.00),
15 new Transaction("15-Jan-2024", "UPI — Meesho Refund", "CREDIT", 899.00),
16 new Transaction("20-Jan-2024", "Electricity Bill", "DEBIT", 1850.00),
17 new Transaction("25-Jan-2024", "Mutual Fund SIP", "DEBIT", 5000.00),
18 new Transaction("28-Jan-2024", "Freelance Payment", "CREDIT", 12500.00),
19 new Transaction("31-Jan-2024", "Broadband Recharge", "DEBIT", 999.00)
20 );
21
22 String statement = StatementGenerator.generate(
23 "Priya Sharma",
24 "HDFC-XXXX-4521",
25 "January 2024",
26 0.0,
27 transactions
28 );
29
30 System.out.println(statement);
31 }
32}Output:
========================================================================
ACCOUNT STATEMENT — PRIYA SHARMA
Account : HDFC-XXXX-4521 Period: January 2024
========================================================================
Date Description Type Amount (Rs.) Balance (Rs.)
------------------------------------------------------------------------
01-Jan-2024 Opening Credit CREDIT +50,000.00 50000.00
03-Jan-2024 Swiggy Food Order DEBIT -649.00 49351.00
05-Jan-2024 Salary Jan 2024 CREDIT +85,000.00 134351.00
08-Jan-2024 EMI - Home Loan DEBIT -22,000.00 112351.00
10-Jan-2024 Amazon Shopping DEBIT -3,499.00 108852.00
15-Jan-2024 UPI — Meesho Refund CREDIT +899.00 109751.00
20-Jan-2024 Electricity Bill DEBIT -1,850.00 107901.00
25-Jan-2024 Mutual Fund SIP DEBIT -5,000.00 102901.00
28-Jan-2024 Freelance Payment CREDIT +12,500.00 115401.00
31-Jan-2024 Broadband Recharge DEBIT -999.00 114402.00
========================================================================
Opening Balance 114402.00
Total Credits 148399.00
Total Debits 33997.00
------------------------------------------------------------------------
Closing Balance 114402.00
========================================================================
Best Practices
Use String.format() when you need the formatted String for further use. Assign the result to a variable, pass it to a method, include it in a larger structure. printf() is fine for quick console output but it does not give you the String back.
Always use %n instead of \n in format strings. %n produces the platform-correct line separator — \r\n on Windows, \n on Unix/Linux/macOS. \n is always Unix-style. For portability, especially when generating text files or reports, %n is the safer choice.
Use %.2f consistently for currency values. A price shown as 1299.5 looks unfinished. %.2f always shows exactly two decimal places — 1299.50. For Indian currency with thousand separators, combine both: %,.2f gives 1,299.50.
Prefer String.formatted() over String.format() for template strings in Java 15+. "Dear %s, your order is ready.".formatted(name) reads more naturally than String.format("Dear %s, your order is ready.", name) — the template and its formatter call are together.
Common Mistakes
Mistake 1 — Argument Count Mismatch
1// Too few arguments — throws MissingFormatArgumentException
2String s = String.format("Name: %s | Age: %d | City: %s", "Priya", 24);
3// Three specifiers but only two arguments — runtime exception
4
5// Too many arguments — extra arguments silently ignored
6String t = String.format("Name: %s", "Priya", "extra", 42);
7// Only "Priya" is used — no error, but confusingMistake 2 — Wrong Type for Specifier
1// %d expects an integer — double throws exception
2String s = String.format("Price: %d", 1299.50); // IllegalFormatConversionException
3
4// Use %f or %.2f for doubles
5String s = String.format("Price: Rs.%.2f", 1299.50); // correctMistake 3 — Using \n Instead of %n for Cross-Platform Output
1// Hard-coded Unix newline — wrong on Windows when writing to files
2String report = String.format("Line1\nLine2\nLine3");
3
4// Correct — platform-appropriate newline
5String report = String.format("Line1%nLine2%nLine3");Mistake 4 — Forgetting %% for a Literal Percent Sign
1// Single % followed by nothing valid — throws exception
2String s = String.format("Discount: 20%"); // MissingFormatArgumentException
3
4// Correct — use %% to produce a literal %
5String s = String.format("Discount: 20%%"); // "Discount: 20%"Interview Questions
Q1. What is String.format() in Java and how does it work?
String.format(template, args...) takes a format string containing format specifiers — placeholders starting with % — and a list of arguments. It replaces each specifier with the corresponding argument, applying the width, precision, and formatting flags specified. The method returns a new formatted String without printing anything. Under the hood, it uses a Formatter object that writes to a StringBuilder. System.out.printf() does the same but writes directly to standard output rather than returning a String.
Q2. What is the difference between %s, %d, and %f in Java format strings?
%s formats any object as a String — it calls String.valueOf() on the argument, which calls toString() for objects. %d formats an integer type — int, long, byte, short — as a decimal number. Passing a double to %d throws IllegalFormatConversionException. %f formats a floating-point number — float or double — with 6 decimal places by default. Use %.2f to control the number of decimal places. These are the three most used specifiers in production Java code.
Q3. How do you format a number with thousand separators and two decimal places in Java?
Use the %, flag combined with .2f precision: String.format("%,.2f", 125000.75) produces 125,000.75. For Indian number formatting (lakhs and crores), use Locale with NumberFormat.getCurrencyInstance(new Locale("en", "IN")) or manually format with String.format which uses the JVM's default locale for the , flag. The default locale on Indian JVMs typically uses Indian grouping.
Q4. What is the difference between System.out.printf() and String.format()?
Both use the same format string syntax and produce the same formatted output. The difference is what they do with it: String.format() returns the formatted text as a String object that you can assign, pass, or store. System.out.printf() writes the formatted text directly to standard output and returns the PrintStream — you cannot capture the formatted String from it. Use String.format() when you need the String for further processing. Use printf() for quick console output.
Q5. How do you left-align and right-align strings with String.format()?
Width alone — %10s — right-aligns the value in a 10-character field. The - flag — %-10s — left-aligns in the same field. For numbers, %10d right-aligns a decimal integer. %010d right-aligns with zero padding. The width specifies the minimum field width — if the value is wider, it is not truncated. The value expands the field. This is how consistently aligned table columns are built: the same width and alignment specifier on every row produces perfectly columnar output.
Q6. What exception is thrown when a format specifier does not match its argument type?
java.util.IllegalFormatConversionException is thrown at runtime when the type of an argument does not match what the specifier expects — for example, passing a double to %d (which expects an integer) or passing a non-boolean to %b. java.util.MissingFormatArgumentException is thrown when there are fewer arguments than format specifiers. Both are runtime exceptions — they are not caught at compile time, so incorrect format strings only fail when executed.
FAQs
Can String.format() handle null arguments?
Yes. For %s, a null argument is formatted as the string "null" — no exception. For other specifiers like %d and %f, null throws NullPointerException — these specifiers require numeric types and cannot represent null. If a numeric field might be null, use %s with String.valueOf(value) or provide a default: value != null ? value : 0.
Is String.format() slow compared to concatenation?
For simple expressions outside loops, the performance difference is negligible. String.format() does parse the format string and uses a Formatter internally, which is slightly more work than a plain +. For tight loops that format thousands of strings, the overhead can add up. In those cases, pre-build the format pattern once and reuse it, or use StringBuilder with manual appends. For most production code — building one or two messages per request — String.format() is perfectly fast.
Can you use format specifiers in log4j or SLF4J log statements?
Logging frameworks like SLF4J use a different placeholder syntax — {} — not %s. logger.info("Processing order {}", orderId) is the SLF4J style. It is lazy — the message is only formatted if that log level is enabled, avoiding unnecessary String creation. String.format() always builds the String regardless of log level. Use {} placeholders in SLF4J/Logback/Log4j2 log statements. Use String.format() for building Strings that go elsewhere — response bodies, error messages, file content.
What does %n produce and why is it different from \n?
%n produces the platform-specific line separator: \r\n on Windows, \n on Linux and macOS. \n always produces a Unix-style newline regardless of platform. For console output, the difference rarely matters — terminals on all platforms handle both. For writing text files, using %n produces files that open correctly in native text editors on all platforms.
Can String.format() be used to build SQL queries?
Technically yes — it can substitute values into a SQL template. But it should not be used for this in production code. Building SQL with string formatting is the classic path to SQL injection vulnerabilities. Use PreparedStatement with ? placeholders for all database queries. The %s specifier in a SQL template does not escape quotes or sanitise input — a malicious value like '; DROP TABLE users; -- would execute. PreparedStatement handles escaping correctly.
Summary
String formatting in Java centres on String.format() and the format specifier syntax. The specifiers — %s, %d, %f, %b, %c, %x, along with width, precision, and flag modifiers — give you full control over how each value appears in the output. printf() uses the same syntax for direct console output. formatted() (Java 15+) attaches the call directly to the template string.
The format specifiers that appear in almost every real codebase: %s for strings, %.2f for currency with two decimal places, %,d or %,.2f for numbers with thousand separators, %-Ns for left-aligned columns in tables, and %n for portable newlines.
For interviews, be ready to explain the difference between String.format() and printf(), demonstrate how to align a table using width and flag specifiers, explain what exceptions are thrown for mismatched types, and write a format string for Indian currency display.
What to Read Next
| Topic | Link |
|---|---|
| How String methods like replace and split complement formatting | Java String Methods → |
| How StringBuilder efficiently builds the same output for large datasets | Java StringBuilder → |
| How String immutability means format() always creates a new object | Java Immutable Strings → |
| How modern Java text blocks replace multi-line string formatting boilerplate | Java Modern Java (8–21) → |
| How String comparison methods work on formatted output | Java String Comparison → |