- Форматирование чисел в Java
- 2. Базовое форматирование чисел с помощью String#format
- 3. Десятичное форматирование путем округления
- 3.1. Использование BigDecimal для форматирования чисел
- 3.2. Использование Math#round
- 4. Форматирование различных типов чисел
- 4.1. Форматирование больших целых чисел с помощью запятых
- 4.2. Дополнение числа
- 4.3. Форматирование чисел с двумя нулями после запятой
- 4.4. Форматирование и проценты
- 4.5. Форматирование номера валюты
- 5. Варианты использования расширенного форматирования
- 6. Заключение
- Форматирование вывода с помощью printf() в Java
- 2. Синтаксис
- 2.1. Правила формата
- 2.2. Преобразование символов
- 2.3. Дополнительные модификаторы
- 3. Разделитель строк
Форматирование чисел в Java
В этом руководстве мы рассмотрим различные подходы к форматированию чисел в Java и способы их реализации.
2. Базовое форматирование чисел с помощью String#format
Метод 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 D = 4.2352989244d; assertThat(withBigDecimal(D, 2)).isEqualTo(4.24); assertThat(withBigDecimal(D, 3)).isEqualTo(4.235);
3.2. Использование Math#round
Мы также можем воспользоваться статическими методами класса Math , чтобы округлить двойное значение до указанного десятичного разряда. В этом случае мы можем настроить количество знаков после запятой, умножив, а затем разделив на 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); >
Мы получаем экземпляр валюты для данной локали , а затем просто вызываем метод форматирования со значением. Результатом является число, отображаемое в качестве валюты для указанной страны:
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. Варианты использования расширенного форматирования
DecimalFormat — один из самых популярных способов форматирования десятичного числа в 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);
Здесь мы позволяем нашему пользователю настроить DecimalFormat по выбранному шаблону на основе количества пробелов.
6. Заключение
В этой статье мы кратко рассмотрели различные способы форматирования чисел в Java. Как мы видим, лучшего способа сделать это не существует. Можно использовать множество подходов, поскольку каждый из них имеет свои особенности.
Как всегда, код этих примеров доступен на GitHub .
Форматирование вывода с помощью printf() в Java
Этот метод является частью класса java.io.PrintStream и обеспечивает форматирование строк, аналогичное функции printf() в C.
2. Синтаксис
Мы можем использовать один из этих методов PrintStream для форматирования вывода:
System.out.printf(format, arguments); System.out.printf(locale, format, arguments);
Мы указываем правила форматирования с помощью параметра формата . Правила начинаются с символа % .
Давайте рассмотрим краткий пример, прежде чем углубляться в детали различных правил форматирования:
System.out.printf("Hello %s!%n", "World");
Это дает следующий результат:
Как показано выше, строка формата содержит обычный текст и два правила форматирования. Первое правило используется для форматирования строкового аргумента. Второе правило добавляет символ новой строки в конец строки.
2.1. Правила формата
Давайте посмотрим на строку формата более внимательно. Он состоит из литералов и спецификаторов формата. Спецификаторы формата включают флаги, ширину, точность и символы преобразования в этой последовательности:
%[flags][width][.precision]conversion-character
Спецификаторы в скобках являются необязательными.
Внутри printf() использует класс java.util.Formatter для разбора строки формата и создания вывода. Дополнительные параметры строки формата можно найти в Javadoc Formatter .
2.2. Преобразование символов
Символ преобразования является обязательным и определяет формат аргумента.
Символы преобразования допустимы только для определенных типов данных. Вот некоторые из них:
- s форматирует строки.
- d форматирует десятичные целые числа.
- f форматирует числа с плавающей запятой.
- t форматирует значения даты/времени.
Мы рассмотрим их и некоторые другие позже в этом руководстве.
2.3. Дополнительные модификаторы
[ Флаги `] ` определяют стандартные способы изменения вывода и чаще всего используются для форматирования целых чисел и чисел с плавающей запятой.
[width] указывает ширину поля для вывода аргумента. Он представляет собой минимальное количество символов, записываемых на выходе.
[.precision] указывает количество разрядов точности при выводе значений с плавающей запятой. Кроме того, мы можем использовать его для определения длины подстроки для извлечения из String .
3. Разделитель строк
Чтобы разбить строку на отдельные строки, у нас есть спецификатор % n :
System.out.printf("foreach%nline%nterminator");
Приведенный выше фрагмент кода выдаст следующий результат: