Форматирование строк в Java: String.format(), printf() и Formatter - Вопросы
Всего: 5 вопросов
1. Чем отличаются String.format(), formatted(), System.out.printf() и класс Formatter в Java?
Чем отличаются String.format(), formatted(), System.out.printf() и класс Formatter в Java?
Все они понимают один и тот же синтаксис шаблона и внутри используют java.util.Formatter. Различаются тем, куда идёт результат:
String.format(шаблон, args...)(Java 5) возвращает новую строку — аналогsprintfиз C;"шаблон".formatted(args...)(Java 15) делает то же, но короче, удобен с текстовыми блоками; перегрузки сLocaleу него нет — всегда используется локаль по умолчанию;System.out.printf()иSystem.out.format()— два имени одного методаPrintStream, печатают сразу в консоль; перевод строки сами не добавляют, его пишут в шаблоне как%n;Formatterнакапливает текст из нескольких вызововformat()и может писать вStringBuilder, файл или поток.
String a = String.format("%s: %d", "Анна", 5);
String b = "%s: %d".formatted("Анна", 5);
System.out.printf("%s: %d%n", "Анна", 5);
StringBuilder sb = new StringBuilder();
Formatter f = new Formatter(sb, Locale.US);
f.format("%-8s%6.2f%n", "Чай", 3.5);
2. Из каких частей состоит спецификатор формата в Java и какие из них обязательны?
Из каких частей состоит спецификатор формата в Java и какие из них обязательны?
Общий вид: %[argument_index$][flags][width][.precision]conversion. Обязательны только знак % и символ преобразования (d, s, f, x…), остальное необязательно:
argument_index$— номер аргумента с 1 (%2$s);%<sберёт тот же аргумент, что предыдущий спецификатор;flags— выравнивание, знак, ведущие нули, разделители групп (-,+,0,,,(,#, пробел);width— минимальная ширина поля: короткое значение дополняется пробелами, длинное выводится целиком;.precision— для дробных число знаков после точки с округлениемHALF_UP, для строк — максимальная длина.
String.format(Locale.US, "[%8.2f]", 1000.0 / 3.0); // [ 333.33]
String.format("[%.3s]", "Formatter"); // [For]
String.format("[%3s]", "Formatter"); // [Formatter]
Заглавные варианты (%S, %X, %B…) переводят результат в верхний регистр; для %d, %f, %o заглавных вариантов нет.
3. Как отформатировать дату через String.format() и почему шаблон "%td.%tm.%tY" с одной датой падает?
Как отформатировать дату через String.format() и почему шаблон "%td.%tm.%tY" с одной датой падает?
Для дат используется спецификатор %t (или %T) с суффиксом: %tY — год, %tm — месяц, %td — день, %tF — дата в формате ISO. Аргументом может быть LocalDate, LocalDateTime, Date, Calendar или long.
Каждый спецификатор без индекса берёт следующий аргумент, поэтому "%td.%tm.%tY" с одной датой ждёт три аргумента и бросает MissingFormatArgumentException. Нужно сослаться на один аргумент через индекс %1$:
LocalDate date = LocalDate.of(2026, 10, 16);
String.format("%tF", date); // 2026-10-16
String.format("%1$td.%1$tm.%1$tY", date); // 16.10.2026
String.format("%td.%tm.%tY", date); // MissingFormatArgumentException
Для сложных форматов дат в современном коде удобнее java.time.format.DateTimeFormatter.
4. Какие ошибки в шаблоне String.format() встречаются чаще всего и какие исключения они вызывают?
Какие ошибки в шаблоне String.format() встречаются чаще всего и какие исключения они вызывают?
Компилятор шаблон не проверяет: ошибки проявляются только при выполнении в виде непроверяемых исключений — наследников IllegalFormatException (он наследует IllegalArgumentException).
String.format("%d", 3.5); // IllegalFormatConversionException: d != java.lang.Double
String.format("%s и %s", "A"); // MissingFormatArgumentException: Format specifier '%s'
String.format("%-05d", 7); // IllegalFormatFlagsException: Flags = '-0'
String.format("%i", 7); // UnknownFormatConversionException: Conversion = 'i'
String.format("Скидка 50%"); // UnknownFormatConversionException, нужно 50%%
String.format("%s", "a", "b"); // исключения нет: "a", лишний аргумент игнорируется
String.format("%d", (Integer) null); // исключения нет: "null"
Флаги - или 0 без ширины дают MissingFormatWidthException. В Java нет %i и %u из C — целые выводятся только через %d.
5. Чем DecimalFormat и MessageFormat отличаются от String.format() и какие у MessageFormat есть подводные камни?
Чем DecimalFormat и MessageFormat отличаются от String.format() и какие у MessageFormat есть подводные камни?
Оба класса из пакета java.text. DecimalFormat задаёт формат числа шаблоном вида #,##0.00, а MessageFormat подставляет аргументы по номерам в фигурных скобках {0}, {1} вместо спецификаторов % — так устроены файлы локализации интерфейса.
DecimalFormat df = new DecimalFormat("#,##0.00",
DecimalFormatSymbols.getInstance(Locale.US));
df.format(1234567.891); // 1,234,567.89
MessageFormat.format("Файл {0} содержит {1} строк", "data.txt", 1500);
// Файл data.txt содержит 1,500 строк
MessageFormat.format("Файл {0} содержит {1,number,#} строк", "data.txt", 1500);
// Файл data.txt содержит 1500 строк
Подводные камни MessageFormat: числа в {1} форматируются по локали с разделителями групп (1500 → 1,500; вывод показан для Locale.US), без разделителей — формат {1,number,#}. Одинарная кавычка в шаблоне служит экранирующим символом, поэтому апостроф нужно удваивать.