string-format: String.format/formatted/printf cheat sheet module (specifier anatomy, rounding vs C printf, locales, Indian lakh/crore grouping Formatter cannot do, format exceptions, %t dates, concat cost), 11 contract tests

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017ic4b7Sr2zcoRD2watXv1G
This commit is contained in:
Claude
2026-11-12 11:00:22 +05:30
parent db129fb1ce
commit 319697c345
29 changed files with 859 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
== conversions: what kind of value ==
text | 42 | 3.141590 | ff | A | true
== width: minimum characters ==
[ ab] [ab ] [ 42] [42 ]
== precision: digits after the point (f), or max chars (s) ==
[3.14] [4] [ 3.142] [abc]
== flags ==
[00042] [+42] [-42] [ 42] [(42)] [1,234,567]
[0xff] [010] [FF] [-003.142]
== argument index: reuse and reorder ==
hello world
echo, echo and again echo
== %n and %% ==
100% sure
next line
== %s accepts anything (calls String.valueOf / toString) ==
[null] [7] [[1, 2]] [SHOUT]
== %b is not 'is this the string true' ==
true true false false
== %c takes a char or a code point ==
A A 😀
+13
View File
@@ -0,0 +1,13 @@
Item Qty Price Total
------------------------------------------------
Notebook 12 45.50 546.00
Pen (box of 10) 3 120.00 360.00
Stapler 1 350.00 350.00
------------------------------------------------
Grand total 1,256.00
== the same table with printf: it prints, it does not return a String ==
Notebook | 12|
== truncation: %.Ns cuts, width pads ==
[Pen (b ] [ Pen (b]
+17
View File
@@ -0,0 +1,17 @@
value %.1f %.2f exact binary value BigDecimal(HALF_EVEN,2)
0.125 0.1 0.13 0.125 0.12
0.25 0.3 0.25 0.25 0.25
0.35 0.4 0.35 0.34999999999999997779 0.35
2.675 2.7 2.68 2.67499999999999982236 2.67
1.005 1.0 1.01 1.00499999999999989341 1.00
0.5 0.5 0.50 0.5 0.50
1.5 1.5 1.50 1.5 1.50
2.5 2.5 2.50 2.5 2.50
== %.0f on halves: HALF_UP, away from zero ==
1 2 3 -3
== same number, three routes: %f rounds what it is given ==
double 2.675 -> 2.68
new BigDecimal("2.675") -> 2.68
new BigDecimal(2.675) -> 2.67
@@ -0,0 +1,30 @@
== what the JDK gives for 123456789 ==
String.format(en_IN, "%,d") : 123,456,789
String.format(hi_IN, "%,d") : 123,456,789
NumberFormat.getInstance(en_IN) : 123,456,789
NumberFormat currency (en_IN) : ₹123,456,789.50
CLDR pattern for en_IN : #,##0.###
== a DecimalFormat pattern that LOOKS like it should work ==
pattern #,##,##0 -> grouping size : 3
pattern #,##,##0 -> output : 123,456,789
== compact formatting knows crore but drops the digits ==
compact (default rounding) : 12Cr
compact (2 fraction digits) : 12.35Cr
== IndianNumberFormat ==
0 -> 0
999 -> 999
1,000 -> 1,000
12,345 -> 12,345
123,456 -> 1,23,456
1,234,567 -> 12,34,567
123,456,789 -> 12,34,56,789
-123,456,789 -> -12,34,56,789
12,34,567.89
-1,00,000.00
Rs. 12,34,567.50
== plugging it into a format string through %s ==
Balance 9,87,65,432.10
+17
View File
@@ -0,0 +1,17 @@
default FORMAT locale: en_US
== %,.2f of 1234567.891 ==
en-US 1,234,567.89
de-DE 1.234.567,89
fr-FR 1^234^567,89
en-IN 1,234,567.89
de-CH 1’234’567.89
und 1,234,567.89
== the bug: changing the default locale changes %.2f ==
default (en_US) : 1234.50
default (de_DE) : 1234,50
explicit ROOT : 1234.50
== not localized: hex, NaN, Infinity ==
ff NaN Infinity
+12
View File
@@ -0,0 +1,12 @@
wrong type for %d -> IllegalFormatConversionException: d != java.lang.String
too few arguments -> MissingFormatArgumentException: Format specifier '%s'
unknown conversion -> UnknownFormatConversionException: Conversion = 'q'
precision on an integer -> IllegalFormatPrecisionException: 2
flag not valid for %x , -> FormatFlagsConversionMismatchException: Conversion = x, Flags = ,
left-justify without width -> MissingFormatWidthException: %-d
zero pad AND left-justify -> IllegalFormatFlagsException: Flags = '-0'
width on %n -> IllegalFormatWidthException: 5
double passed to %d -> IllegalFormatConversionException: d != java.lang.Double
int passed to %f -> IllegalFormatConversionException: f != java.lang.Integer
a stray % in user text -> MissingFormatArgumentException: Format specifier '% o'
extra arguments (no error) -> OK: a
@@ -0,0 +1,22 @@
== four spellings, one result ==
Hi Asha, 3 items, Rs 1499.50
Hi Asha, 3 items, Rs 1499.50
Hi Asha, 3 items, Rs 1499.50
Hi Asha, 3 items, Rs 1499.50
format == formatted == Formatter: true
== formatted() on a text block ==
Invoice for Asha
items : 3
total : 1,499.50
== printf returns the PrintStream, so calls chain ==
one two three
== %n vs \n ==
true on this platform (line.separator is \n)
== an array argument: spread as the varargs, unless you cast it to Object ==
x-1
p-q
true
@@ -0,0 +1,5 @@
JDK 25.0.5, 2000000 iterations per variant, best of 5 rounds
PLUS 52.6 ns/op
BUILDER 66.3 ns/op
FORMATTED 292.1 ns/op
FORMAT 279.5 ns/op
+3
View File
@@ -0,0 +1,3 @@
[INFO] Tests run: 11, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.153 s -- in com.ankurm.stringformat.StringFormatTest
[INFO] Tests run: 11, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
+4
View File
@@ -0,0 +1,4 @@
C printf %.2f of 2.675 : 2.67
C printf %.1f of 0.35 : 0.3
C printf %.2f of 1.005 : 1.00
C printf %.2f of 0.125 : 0.12
+14
View File
@@ -0,0 +1,14 @@
== %t suffixes on a LocalDateTime ==
2026-11-12 | 09:05:07 | 09:05 | 11/12/26
Thursday, 12 November 2026
09:05 AM
== the same suffixes, other locales (names are localized, numbers are not) ==
Donnerstag, 12. November 2026
jeudi 12 novembre 2026
== a LocalDate has no hour ==
IllegalFormatConversionException: H != java.time.LocalDate
== DateTimeFormatter does the same job with a reusable, immutable object ==
12 Nov 2026 09:05