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:
@@ -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 😀
|
||||
@@ -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]
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user