NumberFormat.format: примеры (JAVA)
NumberFormat.format(double number): StringОбщее описание NumberFormat.format
Класс java.text.NumberFormat используется для локализованного преобразования чисел в строку и обратно. Метод format форматирует числовое значение в текст согласно настройкам экземпляра NumberFormat или его подклассов (например, DecimalFormat). Типичное применение - отображение чисел, валюты и процентов с учётом локали, количества дробных знаков, разделителей групп и символов валюты.
Основные варианты вызова и поведение:
- format(double number) - форматирует double и возвращает готовую строку.
- format(long number) - форматирует long и возвращает строку.
- format(Object number) - принимает объект, обычно экземпляр Number; при неподходящем типе может выбросить IllegalArgumentException.
- format(Object number, StringBuffer toAppendTo, FieldPosition pos) - базовый метод из класса Format, который записывает результат в переданный StringBuffer и возвращает его; при этом FieldPosition может использоваться для получения позиции определённого поля (например, целой части).
Настройки NumberFormat, которые влияют на поведение format:
- Locale - влияет на символы десятичного разделителя, разделителя групп и локализованные символы (например, символ валюты).
- setGroupingUsed(boolean) - включение/выключение группировки разрядов (разделение тысяч).
- setMinimumIntegerDigits(int), setMinimumFractionDigits(int), setMaximumFractionDigits(int) - контроль количества цифр в целой и дробной частях.
- setRoundingMode(java.math.RoundingMode) - режим округления при усечении дробной части.
- DecimalFormat.applyPattern(String) - у DecimalFormat можно задать собственный шаблон форматирования (например, "#,##0.00 ¤").
- DecimalFormatSymbols - кастомизация символов (десятичный разделитель, группировщик, символы плюса/минуса и т.д.).
Возвращаемые значения:
- Для format(double/long/Object) возвращается строка с результатом форматирования.
- Для format(Object, StringBuffer, FieldPosition) возвращается тот же StringBuffer, в который добавлен результат.
Примечание: NumberFormat является абстрактным; для получения экземпляра обычно используются фабричные методы: NumberFormat.getInstance(), getCurrencyInstance(), getPercentInstance(), а также версии с указанием Locale.
Короткие примеры использования
Примеры показывают разные варианты форматирования. Код и результат приведены отдельно.
1) Простое форматирование числа
import java.text.NumberFormat;
import java.util.Locale;
public class Ex1 {
public static void main(String[] args) {
NumberFormat nf = NumberFormat.getInstance(Locale.US);
String out = nf.format(12345.678);
System.out.println(out);
}
}
12,345.678
2) Форматирование валюты
import java.text.NumberFormat;
import java.util.Locale;
public class Ex2 {
public static void main(String[] args) {
NumberFormat cf = NumberFormat.getCurrencyInstance(Locale.FRANCE);
System.out.println(cf.format(12345.678));
}
}
12 345,68 €
3) Проценты
import java.text.NumberFormat;
import java.util.Locale;
public class Ex3 {
public static void main(String[] args) {
NumberFormat pf = NumberFormat.getPercentInstance(Locale.US);
pf.setMinimumFractionDigits(1);
System.out.println(pf.format(0.256));
}
}
25.6%
4) DecimalFormat с шаблоном
import java.text.DecimalFormat;
public class Ex4 {
public static void main(String[] args) {
DecimalFormat df = new DecimalFormat("#,##0.00;(#,##0.00)");
System.out.println(df.format(1234567.89));
System.out.println(df.format(-1234567.89));
}
}
1,234,567.89 (1,234,567.89)
5) Использование StringBuffer и FieldPosition
import java.text.FieldPosition;
import java.text.NumberFormat;
public class Ex5 {
public static void main(String[] args) {
NumberFormat nf = NumberFormat.getInstance();
StringBuffer sb = new StringBuffer();
FieldPosition fp = new FieldPosition(NumberFormat.INTEGER_FIELD);
nf.format(12345.67, sb, fp);
System.out.println(sb.toString());
System.out.println("Integer field begins at: " + fp.getBeginIndex());
}
}
12,345.67 Integer field begins at: 0
Похожие Java-решения и их особенности
- DecimalFormat - конкретная реализация NumberFormat с поддержкой шаблонов. Предпочтительнее при необходимости точного шаблонного форматирования (префиксы, суффиксы, разные шаблоны для положительных/отрицательных значений).
- String.format / Formatter - форматирование через форматы типа C ("%,.2f"). Удобно для быстрого вывода без локализованных символов и при форматировании в рамках printf-подобного синтаксиса.
- MessageFormat - форматирование сообщений с подстановкой локализованных чисел; подходит для комбинированных строк и локализации сообщений.
- BigDecimal.toPlainString и методы BigDecimal - используются для точной работы с десятичными значениями, когда важна арифметическая точность; затем можно применять DecimalFormat для представления.
Выбор зависит от требований: для локализации и готовых валют/процентов - NumberFormat; для сложных шаблонов и символов - DecimalFormat; для простого форматирования в стиле printf - String.format.
Аналоги в других языках и отличия
Кратко о популярных альтернативах и примерах кода с результатами.
PHP: number_format
echo number_format(12345.678, 2, '.', ',');
12,345.68
Отличие: простой вызов, не локализованный по умолчанию; для локали используется setlocale/NumberFormatter из intl.
JavaScript: Intl.NumberFormat
console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(12345.678));
12.345,68 €
Отличие: встроенная поддержка локали в рантайме, асинхронные особенности отсутствуют, API похож на Java NumberFormat.
Python: format / locale / babel.numbers
import locale
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
print(locale.format_string('%.2f', 12345.678, grouping=True))
12,345.68
Отличие: стандартный модуль locale зависит от системных локалей; библиотека Babel даёт более гибкую локализацию.
SQL (пример SQL Server): FORMAT
SELECT FORMAT(12345.678, 'N2', 'en-US');
12,345.68
Отличие: форматирование на стороне БД, может быть медленнее при больших объёмах.
C#: ToString с форматами и CultureInfo
using System;
using System.Globalization;
Console.WriteLine(12345.678.ToString("N2", CultureInfo.GetCultureInfo("fr-FR")));
12 345,68
Отличие: встроенная культура и форматы .NET, поведение близко к Java NumberFormat.
Go: fmt и message.Printer
import (
"fmt"
"golang.org/x/text/message"
)
func main() {
p := message.NewPrinter(message.MatchLanguage("en"))
p.Printf("%,.2f", 12345.678)
}
12,345.68
Отличие: базовый fmt не локализует разделители, для локализации нужна внешняя библиотека.
Kotlin
import java.text.NumberFormat
import java.util.Locale
fun main() {
val nf = NumberFormat.getCurrencyInstance(Locale.JAPAN)
println(nf.format(12345.0))
}
¥12,345
Отличие: использует Java API напрямую, синтаксис Kotlin короче.
Lua
-- стандартный string.format
print(string.format("%.2f", 12345.678))
12345.68
Отличие: нет встроенной локализации разделителей; нужны сторонние библиотеки.
Типичные ошибки при использовании
- Попытка форматировать null через формат, принимающий Object, приводит к исключению (NullPointerException или IllegalArgumentException в зависимости от реализации).
- Неправильный тип в format(Object) - если передать не Number, может быть выброшено IllegalArgumentException.
- Неправильный шаблон в DecimalFormat.applyPattern - приводит к IllegalArgumentException при разборе шаблона.
- Неправильная настройка min/max fraction digits - если setMaximumFractionDigits меньше, чем setMinimumFractionDigits, поведение может быть неожиданным; обычно следует сначала задать минимум и максимум согласованно.
- Проблемы многопоточности - экземпляры NumberFormat не потокобезопасны; одновременное использование одного экземпляра из разных потоков может привести к неверному форматированию. Рекомендуется создавать отдельные экземпляры или использовать ThreadLocal.
Примеры ошибок
1) Передача неподходящего объекта
import java.text.NumberFormat;
public class Err1 {
public static void main(String[] args) {
NumberFormat nf = NumberFormat.getInstance();
System.out.println(nf.format("text"));
}
}
Exception in thread "main" java.lang.IllegalArgumentException: Cannot format given Object as a Number
2) Многопоточность (демонстрация некорректного поведения)
// Упрощённый пример: одновременное изменение настроек и форматирование
import java.text.NumberFormat;
public class Err2 implements Runnable {
private static final NumberFormat nf = NumberFormat.getInstance();
public void run() {
for (int i = 0; i < 1000; i++) {
nf.setMinimumFractionDigits(i % 5);
nf.format(12345.678);
}
}
public static void main(String[] args) throws Exception {
new Thread(new Err2()).start();
new Thread(new Err2()).start();
}
}
(поведение неопределено: возможны неверные строки или повреждение внутренних данных)
Изменения и эволюция API
API NumberFormat и DecimalFormat исторически стабильны и сохраняют обратную совместимость. В новых релизах JDK происходили следующие направления развития:
- Расширение набора локалей и улучшение соответствия стандартам локализации (CLDR). Это влияет на вывод символов и шаблонов для разных регионов.
- Появилась и улучшалась поддержка дополнительных стилей форматирования (например, компактное представление чисел в некоторых релизах JDK). Доступность таких возможностей зависит от конкретной версии JDK.
- Улучшена интероперабельность с новыми API локализации и временем выполнения (включая интеграцию с java.time в части локализованных сообщений).
Рекомендуется проверять релиз-ноты конкретной версии JDK для точной информации о новых возможностях и изменениях в поведении форматирования.
Расширенные и редкие варианты использования
Подробные примеры показывают контроль формата, использование FieldPosition для подсветки частей строки, кастомизацию DecimalFormatSymbols, безопасное использование в многопоточной среде и парсинг.
1) Кастомные символы и группы разрядов
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class Adv1 {
public static void main(String[] args) {
DecimalFormatSymbols syms = new DecimalFormatSymbols(Locale.US);
syms.setDecimalSeparator(',');
syms.setGroupingSeparator(' ');
DecimalFormat df = new DecimalFormat("#,##0.000", syms);
System.out.println(df.format(1234567.89123));
}
}
1 234 567,891
2) Форматирование BigDecimal с управлением округлением
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
public class Adv2 {
public static void main(String[] args) {
BigDecimal value = new BigDecimal("2.3455");
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.HALF_UP);
System.out.println(df.format(value));
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(value));
}
}
2.35 2.34
3) Получение атрибутов форматирования (позиции символов)
import java.text.AttributedCharacterIterator;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.AttributedCharacterIterator.Attribute;
public class Adv3 {
public static void main(String[] args) {
NumberFormat nf = NumberFormat.getCurrencyInstance();
StringBuffer sb = new StringBuffer();
FieldPosition fp = new FieldPosition(NumberFormat.INTEGER_FIELD);
nf.format(9876.54, sb, fp);
System.out.println(sb.toString());
// Получение атрибутов через formatToCharacterIterator
AttributedCharacterIterator it = nf.formatToCharacterIterator(9876.54);
it.first();
do {
System.out.print(it.current());
} while (it.next() != AttributedCharacterIterator.DONE);
System.out.println();
}
}
9,876.54 (пример вывода символов с атрибутами; конкретный вывод зависит от локали)
4) ThreadLocal для потокобезопасности
import java.text.NumberFormat;
import java.util.Locale;
public class Adv4 {
private static final ThreadLocal nf = ThreadLocal.withInitial(() -> NumberFormat.getInstance(Locale.US));
public static String format(double v) {
return nf.get().format(v);
}
public static void main(String[] args) {
System.out.println(format(12345.678));
}
}
12,345.678
5) Парсинг с контекстом и контроль ошибок
import java.text.NumberFormat;
import java.text.ParsePosition;
public class Adv5 {
public static void main(String[] args) {
NumberFormat nf = NumberFormat.getInstance();
ParsePosition pp = new ParsePosition(0);
Number n = nf.parse("1234abc", pp);
System.out.println(n); // разобранная часть
System.out.println("Index after parse: " + pp.getIndex());
}
}
1234 Index after parse: 4
6) Встраивание форматирования в шаблон сообщений
import java.text.MessageFormat;
import java.util.Locale;
public class Adv6 {
public static void main(String[] args) {
Object[] objs = {12345.678};
MessageFormat mf = new MessageFormat("Сумма: {0,number,##,##0.00}", Locale.getDefault());
System.out.println(mf.format(objs));
}
}
Сумма: 12,345.68
Эти примеры демонстрируют контроль над локалью, шаблонами, округлением, безопасное использование в многопоточном окружении и получение метаданных о форматированной строке.