NumberFormat.getInstance: примеры (JAVA)

Работа с NumberFormat.getInstance на Java
Раздел: Форматирование чисел и денежных единиц (NumberFormat)
NumberFormat.getInstance: NumberFormat

Описание NumberFormat.getInstance

Метод NumberFormat.getInstance из пакета java.text предоставляет готовый форматтер для представления и разбора чисел с учётом локали. Это статический фабричный метод, возвращающий объект типа NumberFormat. На практике конкретной реализацией чаще всего оказывается java.text.DecimalFormat, имеющий дополнительные возможности по настройке.

Когда применяется

  • Форматирование отображаемых чисел с локальными разделителями десятичных и группировочных разрядов.
  • Разбор строк в числа с учётом локали (например, десятичная запятая в некоторых регионах).
  • Подготовка чисел для отображения пользователю с учётом культурных особенностей.

Сигнатуры и аргументы

  • public static NumberFormat getInstance() - возвращает форматтер для чисел по умолчанию, использующий текущую локаль (Locale.getDefault()).
  • public static NumberFormat getInstance(Locale inLocale) - возвращает форматтер, соответствующий указанной локали inLocale. Если передан null, применяется локаль по умолчанию.

Возвращаемое значение

  • Объект NumberFormat. Он может форматировать методом format(Number) и разбирать методом parse(String).
  • Возвращаемый объект часто является DecimalFormat, что позволяет дополнительно настраивать шаблоны, символы и режимы округления.

Особенности поведения

  • Экземпляры не являются потокобезопасными. Повторное использование одного объекта в нескольких потоках требует синхронизации или создания отдельного экземпляра для каждого потока.
  • Метод parse возвращает Number. Конкретный тип может быть Long, Double, BigDecimal (при соответствующей настройке) и т. д.
  • Некоторые настройки присутствуют в базовом NumberFormat (например, setGroupingUsed, setMaximumFractionDigits). Дополнительные настройки доступны у DecimalFormat (например, setDecimalFormatSymbols, applyPattern, setRoundingMode, setParseBigDecimal).

Ограничения

  • Не предоставляет напрямую форматирования валюты или процентов; для этих задач существуют специализированные фабрики: getCurrencyInstance и getPercentInstance. Однако результат getInstance можно кастовать к DecimalFormat и применять шаблоны.

Короткие примеры использования

1. Базовое форматирование и разбор

import java.text.NumberFormat;
import java.util.Locale;

NumberFormat nf = NumberFormat.getInstance();
String s = nf.format(12345.678);
Number n = nf.parse("12,345.678");
System.out.println(s);
System.out.println(n + " (" + n.getClass().getSimpleName() + ")");
12,345.678
12345.678 (Double)

2. Формат для конкретной локали (Франция: десятичная запятая)

NumberFormat nfFr = NumberFormat.getInstance(Locale.FRANCE);
String sFr = nfFr.format(12345.678);
Number p = nfFr.parse("12 345,678"); // NBSP в группировке
System.out.println(sFr);
System.out.println(p);
12 345,678
12345.678

3. Отключение группировки и ограничение дробных знаков

NumberFormat nfNoGroup = NumberFormat.getInstance();
nfNoGroup.setGroupingUsed(false);
nfNoGroup.setMaximumFractionDigits(2);
System.out.println(nfNoGroup.format(12345.6789));
12345.68

4. Приведение к DecimalFormat для доступа к дополнительным опциям

import java.text.DecimalFormat;
import java.text.NumberFormat;

NumberFormat nf = NumberFormat.getInstance();
if (nf instanceof DecimalFormat) {
    DecimalFormat df = (DecimalFormat) nf;
    df.applyPattern("###,##0.000");
    System.out.println(df.format(12345.6789));
}
12,345.679

Похожие средства в Java

В стандартной библиотеке имеются близкие по назначению фабрики и классы:

  • NumberFormat.getIntegerInstance(Locale)
    • Предназначен для форматирования целых чисел. Дробная часть отбрасывается при форматировании и разборе с учётом настроек.
  • NumberFormat.getCurrencyInstance(Locale)
    • Возвращает форматтер с локализованным символом валюты и правилами отображения. Предпочтителен для вывода цен.
  • NumberFormat.getPercentInstance(Locale)
    • Упрощает вывод процентов, автоматически умножая значение на 100 и добавляя знак процента.
  • DecimalFormat
    • Даёт гибкость настройки шаблонов, символов и режима округления. Используется, когда требуются специфические шаблоны.

Выбор зависит от задачи: для локализованного отображения чисел подойдёт getInstance, для валюты - getCurrencyInstance, для целых чисел - getIntegerInstance. Для детальной настройки шаблонов предпочтительнее использовать DecimalFormat.

Аналоги в других языках и отличия

JavaScript (Intl.NumberFormat)

const nf = new Intl.NumberFormat('fr-FR');
console.log(nf.format(12345.678));
12 345,678

Отличие: API ориентирован на форматирование только; разбор строк в числа требует дополнительных библиотек.

Python (locale и babel)

import locale
locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8')
print(locale.format_string("%0.3f", 12345.678, grouping=True))
12 345,678

Python stdlib обеспечивает простую локализацию, но для продвинутой работы часто используется библиотека babel.numbers, схожая с Java по возможностям.

PHP (number_format и NumberFormatter)

echo number_format(12345.678, 3, '.', ',');
// или с Intl
$fmt = new NumberFormatter('fr_FR', NumberFormatter::DECIMAL);
echo $fmt->format(12345.678);
12,345.678
12 345,678

Отличие: procedural-функция number_format проста, а NumberFormatter из ext-intl предоставляет поведение, близкое к Java.

C# (.NET) (NumberFormatInfo, CultureInfo)

using System;
using System.Globalization;

var ci = new CultureInfo("fr-FR");
Console.WriteLine((12345.678).ToString("N3", ci));
12 345,678

Отличие: .NET имеет богатую поддержку через форматные строки и объекты CultureInfo, аналогично Java по возможностям.

Go (golang.org/x/text/message)

import (
  "fmt"
  "golang.org/x/text/language"
  "golang.org/x/text/message"
)

p := message.NewPrinter(language.French)
p.Printf("%v\n", 12345.678)
12 345,678

Отличие: стандартный пакет fmt не учитывает локаль, для локализованного вывода обычно используется внешний пакет.

Kotlin

import java.text.NumberFormat
import java.util.Locale

val nf = NumberFormat.getInstance(Locale.FRANCE)
println(nf.format(12345.678))
12 345,678

Kotlin работает с тем же API, что и Java, поэтому поведение совпадает.

SQL (пример PostgreSQL)

SELECT to_char(12345.678, 'FM9G999D999') AS formatted;
12,345.678

Отличие: SQL использует собственные функции формата; локаль влияет на разделители через настройки базы.

Типичные ошибки и примеры

1. Ошибка: ожидание потокобезопасности

// Небезопасный пример
private static final NumberFormat NF = NumberFormat.getInstance();

// В многопоточном приложении разные потоки одновременно вызывают NF.format(...)
Возможны некорректные результаты и состояние гонки. Решение: создавать экземпляр на поток или синхронизировать обращения.

2. Ошибка: неверный парсинг из строки с другой локалью

NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
Number n = nf.parse("12,345.678");
System.out.println(n);
12345 (или ParseException в зависимости от входа)
// Входная строка не соответствует ожидаемому формату локали, поэтому результат может быть неожиданным.

3. Ошибка: приведение без проверки типа

NumberFormat nf = NumberFormat.getInstance();
NumberFormat dec = nf; // возможно DecimalFormat
DecimalFormat df = (DecimalFormat) dec; // если реализация другая, возможен ClassCastException
ClassCastException при другой реализации. Рекомендуется проверять instanceof перед приведением.

4. Ошибка: не обрабатывается ParseException

NumberFormat nf = NumberFormat.getInstance();
Number n = nf.parse("abc"); // вызывает ParseException
java.text.ParseException: Unparseable number: "abc"
// ParseException требуется перехватывать или обрабатывать.

Изменения и эволюция

Сам метод NumberFormat.getInstance в API Java остаётся стабильным. В последних версиях Java происходили улучшения в поддержке локалей и поставщиках данных локализации (CLDR), что повлияло на отображение символов и шаблонов в разных локалях. Кроме того, в более новых релизах появились дополнительные фабрики для компактного форматирования чисел (getCompactNumberInstance) и расширенные возможности у DecimalFormat (новые символы, улучшенная поддержка округления). Конкретные изменения зависят от версии JDK и выбранного провайдера локалей.

Продвинутые и редко используемые примеры

1. Разбор в BigDecimal с сохранением точности

Пример java
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.math.BigDecimal;

NumberFormat nf = NumberFormat.getInstance();
if (nf instanceof DecimalFormat) {
    DecimalFormat df = (DecimalFormat) nf;
    df.setParseBigDecimal(true);
    Number n = df.parse("12345.678");
    System.out.println(n.getClass().getName() + " -> " + n);
}
java.math.BigDecimal -> 12345.678

2. Кастомизация символов (замена разделителя)

Пример java
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;

DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.US);
DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
symbols.setDecimalSeparator(',');
symbols.setGroupingSeparator('\u00A0'); // неразрывный пробел
df.setDecimalFormatSymbols(symbols);
System.out.println(df.format(12345.678));
12 345,678

3. Установка режима округления

Пример java
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;

DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
df.setMaximumFractionDigits(2);
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(1.239));
System.out.println(df.format(1.235));
1.23
1.23

4. Частичный разбор с ParsePosition

Пример java
import java.text.NumberFormat;
import java.text.ParsePosition;

NumberFormat nf = NumberFormat.getInstance();
ParsePosition pos = new ParsePosition(0);
Number n = nf.parse("123abc", pos);
System.out.println(n + ", parsed up to index " + pos.getIndex());
123, parsed up to index 3

5. Использование в многопоточном контексте через ThreadLocal

Пример java
import java.text.NumberFormat;

private static final ThreadLocal NF_LOCAL = ThreadLocal.withInitial(NumberFormat::getInstance);

// Внутри потока
NumberFormat nf = NF_LOCAL.get();
System.out.println(nf.format(12345.678));
12,345.678 (в зависимости от локали)

6. Компоновка шаблонов для показа тысячных и малого формата

Пример java
import java.text.DecimalFormat;

DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
df.applyPattern("#,##0.###' 'units");
System.out.println(df.format(12345.678));
12,345.678 units

7. Форматирование для CSV: отключение группировки и фиксированная точность

Пример java
NumberFormat nf = NumberFormat.getInstance();
nf.setGroupingUsed(false);
nf.setMaximumFractionDigits(6);
System.out.println(nf.format(12345.6));
12345.6

8. Сравнение результатов для разных локалей

Пример java
System.out.println(NumberFormat.getInstance(Locale.US).format(12345.678));
System.out.println(NumberFormat.getInstance(Locale.GERMANY).format(12345.678));
System.out.println(NumberFormat.getInstance(Locale.JAPAN).format(12345.678));
12,345.678
12.345,678
12345.678

джава NumberFormat.getInstance function comments

En
NumberFormat.getInstance Returns a general-purpose number format for the current default locale