JavaRush /Java блог /Random UA /Форматуємо виведення чисел у Java

Форматуємо виведення чисел у Java

Стаття з групи Random UA
Всім привіт! Часто до наших методів приходять числа, які потрібно відобразити у якомусь особливому форматі. Начебто як дрібниця, але як би ви реалізували це завдання? Форматуємо виведення чисел у Java - 1Пропонуємо над цим сьогодні трохи поміркувати. Для початку, щоб з головою поринути у форматування чисел у Java, давайте згадаємо метод format класу String : public static String format(String format, Object ... args) - Повертає рядок, відформатований з рядка format за допомогою інших аргументів args . І одразу приклад:
String str = String.format("Привіт %s! Як справи %s?", "Саша", "на роботі");
System.out.println(str);
У результаті ми отримаємо висновок у консолі:
Привіт Саша! Як справи на роботі?

Методи printf та format

String.format() — це не єдиний метод для форматування рядка. Його аналогами можуть бути System.out.printf() і System.out.format(); . Так, попередній код ми можемо замінити на:
System.out.printf("Привіт %s! Як справи %s?", "Саша", "на роботі");
або
System.out.format("Привіт %s! Як справи %s?", "Саша", "на роботі");
Висновок у консолі при цьому залишиться тим самим. Єдиною відмінністю служить лише те, що ці методи відразу виводять значення консолі, на відміну String.format() . Але мені String.format() подобається більше, тому що нам не завжди потрібно виводити результат у консолі, тому далі ми використовуватимемо саме цей спосіб. Повернімося до нашого прикладу. Що ми бачимо? А те, що в місця, де були символи - %s , вставлені рядки - "Саша" та "на роботі". Яким чином це може нам допомогти при розробці? Уявіть, що у вас є великий шаблонний текст, але в деяких місцях потрібно вставляти значення, які можуть бути різними і приходити в якості аргументів ззовні. Ось тут нам і знадобиться це форматування. Специфікатори формату починаються зі знака відсотка % і закінчуються символом, що вказує на тип аргументу, який потрібно відформатувати. І, як ви, напевно, зрозуміли, %s використовується для вставки об'єктів — рядків. Але якщо ми спробуємо вставити, наприклад, double в місце, де прописаний об'єкт рядка:
String str = String.format("Привіт %s! Як справи %s?", 55.6, "на роботі");
це також спрацює. double буде приведено до рядка, і ми отримаємо:
Привіт – 55.6! Як справи на роботі?
Крім рядків і чисел з плаваючою комою, у Java є й інші типи, чи не так? Тож давайте поглянемо на весь арсенал:
Тип форматованого значення приклад
%s Будь-який тип, який буде приведений до рядка
String.format("Привіт %s!","мир")
Результат:
Привіт світ!
%b Будь-який тип, який буде приведений до boolean : true – якщо значення не null, false – якщо null
String.format("Привіт %b!",null)
Результат:
Привіт false
%h Можна передавати будь-який об'єкт, який буде приведений до шістнадцяткового рядка значення з методу hashCode ()
String.format("Привіт %h!","мир")
Результат:
Привіт 106C44!
%c Використовується для завдання символу Unicode ( char )
String.format("Привіт м%cр!",'і')
Результат:
Привіт світ!
%d Задається ціле число ( int. byte, short, int, long, BigInteger )
String.format("Мені вже %d!",20)
Результат:
Мені вже 20!
%f Використовується для завдання числа з плаваючою комою
String.format("Кількість ПІ дорівнює - %f!", 3.14159)
Результат:
Число ПІ дорівнює - 3,141590!
%e Числа з плаваючою комою в експоненційному поданні
String.format("Кількість ПІ дорівнює - %e!", 3.14159);
Результат:
Число ПІ дорівнює - 3,141590e+00!
%a Числа з плаваючою комою будуть представлені у шістнадцятковому вигляді
String.format("Кількість ПІ дорівнює - %a!", 3.14159)
Результат:
Число ПІ дорівнює - 0x1.921f9f01b866ep1!
%x Передається ціле число ( int. byte, short, int, long, BigInteger ), результатом форматування буде символ під цим номером у таблиці ASCII
String.format("Мені вже %x!",25)
Результат:
Мені вже 19!
%o Приймається ціле число ( int. byte, short, int, long, BigInteger ), яке буде представлено у вигляді восьмеричного числа
String.format("Мені вже %o!",25);
Результат:
Мені вже 31!
%t Префікс для перетворення дати та часу. Для форматування потрібні додаткові прапори
String.format("Сьогодні %tA",new Date())
Результат:
Сьогодні субота
%n Розділювач рядків для конкретної платформи. Аналог \n
String.format(" Привіт %n Привіт")
Результат:
Привіт привіт
Давайте використовуємо для double більш відповідний формат:
String str = String.format("Відстань від Києва до Одеси - %f. Не так уже й мало, чи не так?", 475.4d);
System.out.println(str);
Виведення в консоль:
Відстань від Києва до Одеси – 475,400000. Не так уже й мало, чи не так?
Як ви вже зрозуміли, %f буде більш відповідним специфікатором для чисел з плаваючою комою, які включають такі типи даних як double і float в Java. З цим специфікатором ми можемо форматувати число з плаваючою комою:
String str = String.format("Відстань від Києва до Одеси - %.2f. Не так уже й мало, чи не так?", 475.4d);
Вставка .2 в даний специфікатор обріже кількість знаків після коми до двох, і ми отримаємо висновок:
Відстань від Києва до Одеси – 475,40. Не так уже й мало, чи не так?
.2 - не єдина підналаштування специфікаторів. Комбінація даних підналаштувань називається інструкцією . Форматуємо виведення чисел у Java - 2Загальний вигляд інструкції такий:
%[аргумент_індекс][прапори][ширина][.точність]специфікатор типу
А тепер розшифруємо все по порядку:
  • [аргумент_індекс] — ціле число, що вказує на позицію в списку аргументів. Наприклад, посилання перший аргумент 1$, посилання другий аргумент — 2$, тощо. Якщо ж позиція не була задана, аргументи повинні бути в тому ж порядку, що й посилання на них у форматі.
  • [Прапори] — спеціальні символи для форматування. Наприклад:
    • + прапор, що означає, що якщо числове значення позитивне, воно має містити знак +
    • - означає вирівнювання результату з лівого краю
    • , встановлює роздільник тисяч у цілих чисел
  • [Ширина] — позитивне ціле десяткове число, що визначає мінімальну кількість символів, які будуть виведені. Якщо перед цим числом стоїть 0, то символи, що відсутні, будуть доповнені 0, якщо 0 ні, то пробілами.
  • [. Точність] - невід'ємне ціле число з точкою перед ним. Як правило, використовується для обмеження кількості символів. Специфіка поведінки залежить від виду специфікатора.
Також хотілося б відзначити, що всі перелічені вище елементи інструкції не обов'язкові, і все буде працювати і без них. Як приклад використання підналаштувань уявімо, що нам потрібен специфічний висновок числа Пі:
String str = String.format("%1$+09.5f", 3.1415926535897);
System.out.print(str);
І, відповідно, висновок у консолі:
+03,14159
Начебто нескладно, так? Але коли йдеться про форматування числа, то не можна обійти стороною DecimalFormat . Давайте розберемося, що мають на увазі.

DecimalFormat

DecimalFormat - клас для форматування будь-якого числа в Java, чи то ціле число, чи число з плаваючою комою. Коли відбувається створення об'єкта DecimalFormat , прямо в конструкторі можна задати шаблон форматування чисел, що приходять. Як буде виглядати наш приклад з використанням DecimalFormat :
DecimalFormat dF = new DecimalFormat( "#.###" );
double value = 72.224463;
System.out.print(dF.format(value));
Висновок у консолі:
72,224
Рядок #.### є шаблоном, який вказує, що ми форматуємо значення, що передається, до 3 десяткових знаків. Які ще є символи для шаблонів? Ось деякі з них:
  • # - цифра, що ведуть нулі опускаються;
  • 0 — цифра завжди відображається, навіть якщо в номері менше цифр (у такому випадку відображається 0);
  • . - Знак десяткового роздільника;
  • , - Знак угруповання роздільників (наприклад, роздільник тисяч);
  • ; - Поділяє формати;
  • - - Зазначає префікс негативного числа;
  • % - множить на 100 і показує число у відсотках;
  • ? - множить на 1000 і показує число у проміле;
  • E – розділяє мантису та порядок для експоненційного формату.
Погляньмо на кілька прикладів:
System.out.println(new DecimalFormat( "###,###.##" ).format(74554542.224463));
Висновок у консолі:
74 554 542,22
System.out.println(new DecimalFormat( "%###.##" ).format(0.723456));
Висновок у консолі:
%72,35
System.out.println(new DecimalFormat( "000.###" ).format(42.224463));
Висновок у консолі:
042,224
Не обов'язково створювати щоразу новий об'єкт DecimalFormat , щоб задати новий шаблон. Досить використовувати його методи applyPattern і applyLocalizedPattern :
DecimalFormat dF = new DecimalFormat("###.###");
dF.applyPattern("000000.000");
dF.applyLocalizedPattern("#,#00.0#");
Коли ми говоримо про форматування числа з плаваючою комою, нас чимало цікавить округлення, чи не так? Так ось, при обрізанні числа зі знаками після коми, що виходять за заданий шаблон, DecimalFormat округляє число у більшу сторону, якщо останнє число, що обрізається, більше 5. А якщо останнє обрізуване - 5? Адже в такому разі це число рівно посередині між найближчими цілими. Форматуємо виведення чисел у Java - 3У цьому випадку до уваги береться попереднє до нього число. Якщо попереднє число парне, округлення провадиться:
DecimalFormat dF = new DecimalFormat("##.###");
String result = dF.format(56.4595);
System.out.println((result));
Висновок у консолі:
56,459
Якщо непарне — не робиться:
DecimalFormat dF = new DecimalFormat("##.###");
String str = dF.format(56.4595);
System.out.println((str));
Висновок у консолі:
56,459
Різницею між форматуванням чисел з плаваючою комою з використанням String.format() і DecimalFormat.format() можна вважати те, що в першому випадку будуть присутні кінцеві нулі, навіть якщо немає дробової частини. Наприклад:
String firstStr = String.format("%.4f", 9.00001273);
System.out.println((firstStr));
Висновок у консолі:
9,0000
DecimalFormat decimalFormat = new DecimalFormat("#.####");
String secondStr = decimalFormat.format(9.00001273);
System.out.println((secondStr));
Висновок у консолі:
9
Як бачите, при форматуванні числа 9.00001273 з точністю до чотирьох десяткових розрядів метод format() у класу String виведе значення 9.0000 , при цьому у DecimalFormat аналогічний метод format() виведе 9 .

BigDecimal та BigInteger

Якщо ми торкнулися такої теми округлення чисел у Java, поговоримо і про те, як для таких операцій використовувати клас BigDecimal . Цей клас орієнтований працювати з справді ВЕЛИКИМИ числами: йому максимальні значення double і float занадто малі. Цей клас має багато різних налаштувань для округлення числа з плаваючою комою, а також багато методів для арифметичних операцій. Він має схожий клас, але орієнтований працювати з ВЕЛИКИМИ цілими числами — BigInteger . Докладніше про BigDecimal та BigInteger можна почитати в цій статті .

Форматування Date та Time

Вище згадувалося, що за допомогою format() класу String можна ще й форматувати час і дату. Форматуємо виведення чисел у Java - 4Що ж, погляньмо, як це робиться. По-перше, хотілося б нагадати, що для дат використовується специфікатор формату %t . По-друге, при форматуванні шаблону для кожного специфікатора формату для дат потрібні додаткові прапори форматування. Ось можливі прапори форматування для дат:
Прапори Опис
%tB Повна назва місяця, наприклад January, February і т.д.
%tb Скорочену назву місяця, наприклад, Jan, Feb тощо.
%tA Повна назва дня тижня, наприклад, Sunday, Monday
%ta Скорочену назву дня тижня, наприклад, Sun, Mon тощо.
%tY Рік у форматі 4 цифри, наприклад, від 0000 до 9999
%ty Рік у форматі 2 цифри, наприклад, від 00 до 99
%tm Місяць відформатовано з нуля на початку, наприклад, від 01 до 12
%tc Дата та час у форматі %ta %tb %td %tT %tZ %tY, наприклад, Mon Feb 17 03:56:12 PST 2020
%tD Дата у форматі %tm/%td/%ty
%td День місяця у форматі двох цифр, наприклад, від 01 до 31
%te День місяця у форматі без 0 на початку, наприклад, від 1 до 31
%tT Час у 24-годинному форматі, наприклад, %tH:%tM:%tS
%tH Година дня у 24-годинному форматі, від 00 до 23
%tI Година дня для 12-годинного формату, наприклад, від 01 до 12
%tM Хвабони за годину форматуються з нуля на початку, наприклад, від 00 до 59
%tS Секунди за хвабону, що складаються з двох цифр, наприклад, від 00 до 59
%tZ Абревіатура часового поясу, наприклад PST, UTC і т.д.
Це скорочений список можливих прапорів форматування дат – їх дуже багато, на будь-який смак. Повний список їх як і можливих специфікаторів можна переглянути за цим посиланням . Давайте розглянемо, як користуватися цим. На цей раз використовуємо не String.format() , а відразу System.out.printf() .

Приклад 1

Крім того, поставимо мову результату, передавши її першим аргументом у спосіб:
Date date = new Date();
System.out.printf(Locale.ENGLISH,"%tB %te, %tY",date,date,date);
Висновок у консолі:
October 11, 2020
Без задання мови буде використана мова за умовчанням (наприклад, у мене вона російська).

Приклад 2

Давайте виведемо на екран більш повну дату:
Date date = new Date();
System.out.printf("%td %tB %tY року %n%tH:%tM:%tS",date,date,date,date,date,date,date);
І висновок у консолі:
11 жовтня 2020 13:43:22
Стільки разів передавати аргументом один і той самий об'єкт Date... Якось виглядає не дуже, чи не так? Давайте скористаємося внутрішньою підналаштуванням $ для вказівки аргументу, який ми хочемо використовувати:
System.out.printf("%1$td %1$tB %1$tY року %n%1$tH:%1$tM:%1$tS",date);
Висновок у консолі у нас і не зміниться. Є й інші не менш цікаві способи форматування дати. Про них і трохи докладніше про час і дату в Java можна почитати ось у цьому матеріалі . На цьому у мене на сьогодні все, дякую за увагу!Форматуємо виведення чисел у Java - 5
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ