Рубрики
Без рубрики

Форматирование чисел в Java

Научитесь форматировать числа на Java.

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы рассмотрим различные подходы к форматированию чисел в Java и способы их реализации.

2. Базовое форматирование чисел с форматом строки#

Метод String#format очень полезен для форматирования чисел. Метод принимает два аргумента. Первый аргумент описывает шаблон о том, сколько десятичных знаков мы хотим видеть, а второй аргумент-это заданное значение:

double value = 4.2352989244d;
assertThat(String.format("%.2f", value)).isEqualTo("4.24");
assertThat(String.format("%.3f", value)).isEqualTo("4.235");

3. Десятичное форматирование путем округления

В Java у нас есть два примитивных типа, которые представляют десятичные числаfloat и decimal :

double myDouble = 7.8723d;
float myFloat = 7.8723f;

Количество знаков после запятой может отличаться в зависимости от выполняемых операций. В большинстве случаев нас интересуют только первые два знака после запятой . Давайте рассмотрим некоторые способы форматирования десятичной дроби путем округления.

3.1. Использование BigDecimal для форматирования чисел

Класс BigDecimal предоставляет методы округления до заданного числа десятичных знаков. Давайте создадим вспомогательный метод, который вернет двойное, округленное до нужного количества мест:

public static double withBigDecimal(double value, int places) {
    BigDecimal bigDecimal = new BigDecimal(value);
    bigDecimal = bigDecimal.setScale(places, RoundingMode.HALF_UP);
    return bigDecimal.doubleValue();
}

Мы начинаем с нового экземпляра BigDecimal с нашим исходным десятичным значением. Затем, установив масштаб, мы указываем количество знаков после запятой, которое мы хотим, и как мы хотим округлить наше число . Использование этого метода позволяет нам легко форматировать значение double :

double D = 4.2352989244d;
assertThat(withBigDecimal(D, 2)).isEqualTo(4.24);
assertThat(withBigDecimal(D, 3)).isEqualTo(4.235);

3.2. Использование Math#round

Мы также можем воспользоваться статическими методами в классе Math |, чтобы округлить значение double до указанного десятичного знака. В этом случае мы можем настроить количество десятичных знаков путем умножения и последующего деления на 10^n . Давайте проверим наш вспомогательный метод:

public static double withMathRound(double value, int places) {
    double scale = Math.pow(10, places);
    return Math.round(value * scale) / scale;
}
assertThat(withMathRound(D, 2)).isEqualTo(4.24);
assertThat(withMathRound(D, 3)).isEqualTo(4.235);

Однако этот способ рекомендуется только в особых случаях, так как иногда выходные данные могут быть округлены иначе, чем ожидалось до их печати.

Это происходит потому, что Math#round усекает значение . Давайте посмотрим, как это может произойти:

System.out.println(withMathRound(1000.0d, 17));
// Gives: 92.23372036854776 !!
System.out.println(withMathRound(260.775d, 2));
// Gives: 260.77 instead of expected 260.78

Таким образом, метод указан только в учебных целях.

4. Форматирование различных типов чисел

В некоторых конкретных случаях мы можем захотеть отформатировать число для определенного типа, такого как валюта, большое целое число или процент.

4.1. Форматирование Больших Целых Чисел Запятыми

Всякий раз, когда у нас есть большое целое число в нашем приложении, мы можем захотеть отобразить его с запятыми, используя DecimalFormat с предопределенным шаблоном:

public static String withLargeIntegers(double value) {
    DecimalFormat df = new DecimalFormat("###,###,###");
    return df.format(value);
}

int value = 123456789;
assertThat(withLargeIntegers(value)).isEqualTo("123,456,789");

4.2. Заполнение номера

В некоторых случаях мы можем захотеть дополнить число нулями заданной длины. Здесь мы можем использовать метод String#format , как описано ранее:

public static String byPaddingZeros(int value, int paddingLength) {
    return String.format("%0" + paddingLength + "d", value);
}

int value = 1;
assertThat(byPaddingOutZeros(value, 3)).isEqualTo("001");

4.3. Форматирование чисел С Двумя Нулями После запятой

Чтобы иметь возможность печатать любое заданное число с двумя нулями после десятичной точки, мы будем использовать еще один раз DecimalFormat класс с предопределенным шаблоном:

public static double withTwoDecimalPlaces(double value) {
    DecimalFormat df = new DecimalFormat("#.00");
    return new Double(df.format(value));
}

int value = 12; 
assertThat(withTwoDecimalPlaces(value)).isEqualTo(12.00);

В этом случае мы создали новый формат с шаблоном, указывающим два нуля после десятичной точки .

4.4. Форматирование и проценты

Время от времени нам может понадобиться отображать проценты.

В этом случае мы можем использовать метод NumberFormat# getPercentInstance . Этот метод позволяет нам указать Locale для печати значения в формате, соответствующем указанной вами стране:

public static String forPercentages(double value, Locale locale) {
    NumberFormat nf = NumberFormat.getPercentInstance(locale);
    return nf.format(value);
}

double value = 25f / 100f;
assertThat(forPercentages(value, new Locale("en", "US"))).isEqualTo("25%");

4.5. Форматирование Номера Валюты

Распространенным способом хранения валют в нашем приложении является использование BigDecimal . Что делать, если мы хотим отобразить их пользователю? В этом случае мы можем использовать класс NumberFormat :

public static String currencyWithChosenLocalisation(double value, Locale locale) {
    NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
    return nf.format(value);
}

Мы получаем экземпляр валюты для заданного Locale , а затем просто вызываем метод format со значением. Результатом является число, отображаемое в качестве валюты для указанной страны:

double value = 23_500;
assertThat(currencyWithChosenLocalisation(value, new Locale("en", "US"))).isEqualTo("$23,500.00");
assertThat(currencyWithChosenLocalisation(value, new Locale("zh", "CN"))).isEqualTo("¥23,500.00");
assertThat(currencyWithChosenLocalisation(value, new Locale("pl", "PL"))).isEqualTo("23 500 zł");

5. Расширенные варианты использования форматирования

Десятичный формат – один из самых популярных способов форматирования десятичного числа в Java. Как и в предыдущих примерах, мы напишем вспомогательный метод:

public static double withDecimalFormatLocal(double value) {
    DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(Locale.getDefault());
    return new Double(df.format(value));
}

Наш тип форматирования получит настройку по умолчанию для данной локализации.

Десятичное форматирование обрабатывается по-разному в разных странах с использованием их числовых систем. Например, символ группировки (запятая в США, но пробел или точка в других языках), размер группировки (три в США и большинстве языков, но разные в Индии) или десятичный символ (точка в США, но запятая в других языках).

double D = 4.2352989244d;
assertThat(withDecimalFormatLocal(D)).isEqualTo(4.235);

Мы также можем расширить эту функциональность, чтобы предоставить некоторые конкретные шаблоны:

public static double withDecimalFormatPattern(double value, int places) {
    DecimalFormat df2 = new DecimalFormat("#,###,###,##0.00");
    DecimalFormat df3 = new DecimalFormat("#,###,###,##0.000");
    if (places == 2)
        return new Double(df2.format(value));
    else if (places == 3)
        return new Double(df3.format(value));
    else
        throw new IllegalArgumentException();
}

assertThat(withDecimalFormatPattern(D, 2)).isEqualTo(4.24); 
assertThat(withDecimalFormatPattern(D, 3)).isEqualTo(4.235);

Здесь мы позволяем нашему пользователю настроить Десятичный формат по выбранному шаблону на основе количества пробелов.

6. Заключение

В этой статье мы кратко рассмотрели различные способы форматирования чисел в Java. Как мы видим, нет лучшего способа сделать это. Можно использовать множество подходов, поскольку каждый из них имеет свои особенности.

Как всегда, код для этих примеров доступен на GitHub .