Files
..

string-format

Companion code for the ankurm.com post "String.format, formatted() and printf in Java: The Complete Cheat Sheet." Module in java-core-examples, the Java-core series.

Versions this was built and tested against

Component Version Notes
JDK 25.0.5+8 (Temurin, LTS) String.format is Java 5; String.formatted() arrived in Java 15; Formatter parsing was rewritten without regex in Java 17.
JUnit Jupiter 5.11.0
Maven 3.9.11

Quickstart

export JAVA_HOME=/path/to/jdk-25
mvn compile
scripts/run.sh IndianGroupingDemo      # one demo
scripts/run-all.sh                     # regenerate every file in output/

What's in here

File What it shows
BasicsDemo.java Every part of %[index$][flags][width][.precision]conversion, changed one at a time.
ReportTableDemo.java Left/right alignment, zero padding, truncation with %.Ns, a fixed-width invoice, printf.
RoundingDemo.java %f rounds HALF_UP on the decimal string, so it disagrees with C printf and with BigDecimal(double).
IndianNumberFormat.java + IndianGroupingDemo.java The main exhibit. Every built-in route to lakh/crore grouping tried and shown to fail, then a 60-line formatter that works.
LocaleDemo.java The same %,.2f under six locales; the default-locale trap; what is not localized.
FormatErrorsDemo.java Twelve format strings that compile and then throw (or, for "50% off", throw something surprising), with the real exception text.
FormattedAndPrintfDemo.java format / formatted / printf / Formatter are one engine; text-block pairing; varargs and arrays.
DateTimeDemo.java %tF, %tT, %tA on java.time values, localized names, and why %tH on a LocalDate throws.
ConcatBenchmarkDemo.java Indicative cost of +, StringBuilder, formatted, format. A warmed plain loop, not JMH.
StringFormatTest.java Pins every claim above as an assertion, 11/11 passing.
scripts/printf_compare.c The same values through C printf, for the rounding comparison.
output/01-11 Captured runs of everything above. Timing in 08 drifts between runs.

Notes worth knowing before reading the post

  • %,d cannot produce lakh/crore grouping in any locale. en_IN and hi_IN both print 123,456,789 (output/04). The , flag takes one grouping size from DecimalFormat.getGroupingSize(), and a DecimalFormat built from #,##,##0 reports a grouping size of 3.
  • "Discount 50% off" throws MissingFormatArgumentException, not an unknown-conversion error: % o parses as the space flag plus the octal conversion (output/06).
  • %f on a double rounds the decimal string, %f on a BigDecimal rounds the exact value, so 2.675 formats as 2.68 one way and 2.67 the other (output/03).

License

MIT - see the repo-wide LICENSE.