What is DecimalFormat and how do its pattern symbols (0, #, comma, dot) control the output?
answer
- 0 = required digit (pads), # = optional digit (drops)
- comma sets grouping size by distance to the dot
- pattern . and , are placeholders, glyphs come from symbols/locale
- ; separates positive;negative sub-patterns
- % multiplies by 100
basics
~20 sDecimalFormat is a concrete NumberFormat that formats numbers from a pattern string. In the pattern, 0 forces a digit (shows zero if absent), # shows a digit only if present, the comma marks grouping, and the dot marks the decimal point. So "#,##0.00" gives grouped numbers with exactly two decimals.
solid answer
~50 sDecimalFormat is the main concrete subclass of NumberFormat and lets you specify formatting with a pattern. The core symbols: 0 is a required digit placeholder (prints 0 if the number lacks one), # is an optional digit (prints nothing if absent), the period is the decimal separator placeholder, the comma sets the grouping size, and characters like % or currency markers apply scaling/symbols. For example new DecimalFormat("#,##0.00").format(1234.5) yields "1,234.50" — grouping every three digits and forcing two fraction digits. A pattern can also have a positive;negative sub-pattern separated by a semicolon. Crucially the literal characters you write (. and ,) are placeholders, not the actual output characters: the real separators come from the locale's DecimalFormatSymbols, so the same pattern renders "1.234,50" in Germany. That separation of pattern (structure) from symbols (locale glyphs) is the design's key idea.
code
java · 10 linesDecimalFormat f = new DecimalFormat("#,##0.00");
f.format(1234.5); // "1,234.50" (forced 2 decimals + grouping)
f.format(0.5); // "0.50" (0 prints the leading zero)
DecimalFormat g = new DecimalFormat("#.##");
g.format(1234.5); // "1234.5" (no grouping, trailing zero dropped)
g.format(3.0); // "3" (# drops absent/zero fraction)
DecimalFormat neg = new DecimalFormat("#,##0.00;(#,##0.00)");
neg.format(-42); // "(42.00)" (custom negative sub-pattern)go deeper
Recognizes a DecimalFormat pattern and can read that 0 forces a digit and # is optional.
Writes correct patterns for grouping and fixed decimals, knows 0 vs # and the comma grouping rule.
Explains pattern-vs-symbols separation, negative sub-patterns, quoting, and the default-locale pitfall of the no-symbol constructor.
Standardizes pattern usage, decides between DecimalFormat and higher-level i18n libraries, and reviews for locale-determinism and rounding policy.
## Where DecimalFormat fits `NumberFormat` (covered separately) is the abstract factory; `DecimalFormat` is its main **concrete** subclass and the one you reach for when the canned factories (currency, percent, integer) aren't enough and you need an exact, custom shape. You typically build it with a **pattern string**: `new DecimalFormat("#,##0.00")`. ## The pattern alphabet A pattern is a tiny mini-language. The symbols you must know: - **`0`** — a *required* digit. If the number has no digit in that position, a `0` is printed anyway. So `"00"` formats `5` as `"05"` (zero-padding) and forces minimum decimals: `"0.00"` formats `3` as `"3.00"`. - **`#`** — an *optional* digit. A digit prints only if the number actually has one there; otherwise nothing. So `"#.##"` formats `3` as `"3"` and `3.5` as `"3.5"`. - **`.`** (period) — marks where the **decimal separator** goes. There is at most one. - **`,`** (comma) — marks the **grouping** position. Its distance from the decimal point sets the group size; `"#,##0"` groups every 3 digits. - **`%`** — multiplies the value by 100 and shows a percent sign. - **`‰`** — per-mille (multiply by 1000). - **`'`** (apostrophe) — quotes literal text so it isn't interpreted, e.g. `"#'%' done"`. - **`;`** — separates the positive sub-pattern from a custom **negative** sub-pattern: `"#,##0.00;(#,##0.00)"` shows negatives in parentheses. ## Pattern vs. symbols — the crucial separation The `.` and `,` you type in the pattern are **placeholders describing structure**, not the literal glyphs in the output. The actual characters come from a `DecimalFormatSymbols` object tied to the **Locale**. So a single pattern `"#,##0.00"`: ```java DecimalFormat us = new DecimalFormat("#,##0.00", DecimalFormatSymbols.getInstance(Locale.US)); DecimalFormat de = new DecimalFormat("#,##0.00", DecimalFormatSymbols.getInstance(Locale.GERMANY)); us.format(1234.5); // "1,234.50" de.format(1234.5); // "1.234,50" (comma and dot swap roles) ``` This is why you keep one pattern but vary the symbols per locale. Note: `new DecimalFormat(pattern)` with no symbols uses the **default locale's** symbols — the same default-locale hazard as NumberFormat. ## Reading a pattern `"#,##0.00"` decodes as: optional digits with grouping (`#,##`), at least one integer digit (`0`), a decimal point, and exactly two required fraction digits (`00`). Minimum integer digits = 1, minimum fraction digits = 2, maximum fraction digits = 2. ## Common patterns - `"0"` — integer, at least one digit. - `"0.00"` — always two decimals. - `"#,##0"` — grouped integer. - `"#,##0.##"` — grouped, up to two decimals, trailing zeros dropped. - `"0.00%"` — percentage with two decimals. ## Key takeaways 1. `0` = required digit (pads/forces), `#` = optional digit (drops). 2. `,` sets grouping size by its distance to the `.`. 3. The literal `.`/`,` are placeholders; real glyphs come from locale symbols. 4. `;` adds a negative sub-pattern; `'...'` quotes literals. 5. No-symbol constructor uses the default locale — pass `DecimalFormatSymbols` explicitly for determinism.
- What does the pattern "#,##0.##" do to the value 1500?It outputs "1,500". Grouping is applied, the integer part shows fully (minimum one digit via the 0), and because the fraction digits are # they are dropped when zero.
- How do you make negative numbers appear in parentheses?Use a semicolon sub-pattern: new DecimalFormat("#,##0.00;(#,##0.00)"). The part after ; is the negative form; the minus sign is implied so you write the parentheses literally.
saying these in an interview costs you the question
- Believing the dot/comma in the pattern are the literal output characters
- Confusing 0 and # (using # where you needed zero-padding)
- Forgetting the no-symbol constructor uses the default locale
- Thinking DecimalFormat is abstract like NumberFormat