Java Tutorial
🔍

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.

Java
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.

Java
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.

Java
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.

Java
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.

Java
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.

Java
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

SpecifierTypeExampleOutput
%sString"Hello %s".formatted("World")Hello World
%SString uppercase"%S".formatted("java")JAVA
%dDecimal int"%d".formatted(42)42
%05dZero-padded int"%05d".formatted(42)00042
%,dInt with separator"%,d".formatted(1000000)1,000,000
%fFloat (6dp)"%f".formatted(3.14)3.140000
%.2fFloat (2dp)"%.2f".formatted(3.14159)3.14
%,.2fFloat + separator"%,.2f".formatted(99999.9)99,999.90
%eScientific"%e".formatted(12345.6)1.234560e+04
%10sRight-aligned"%10s".formatted("hi")__________hi (8 spaces)
%-10sLeft-aligned"%-10s".formatted("hi")hi__________ (8 spaces)
%bBoolean"%b".formatted(true)true
%cCharacter"%c".formatted('A')A
%xHex lowercase"%x".formatted(255)ff
%XHex uppercase"%X".formatted(255)FF
%nNewline"Line1%nLine2"Two lines
%%Literal %"100%%"100%
%+.2fAlways 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.

Java
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}
Java
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}
Java
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

Java
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 confusing

Mistake 2 — Wrong Type for Specifier

Java
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); // correct

Mistake 3 — Using \n Instead of %n for Cross-Platform Output

Java
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

Java
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

TopicLink
How String methods like replace and split complement formattingJava String Methods →
How StringBuilder efficiently builds the same output for large datasetsJava StringBuilder →
How String immutability means format() always creates a new objectJava Immutable Strings →
How modern Java text blocks replace multi-line string formatting boilerplateJava Modern Java (8–21) →
How String comparison methods work on formatted outputJava String Comparison →
Java String Formatting | DevStackFlow