Руководство по java.util.Formatter

Руководство по java.util.Formatter

1. обзор

В этой статье мы обсудим форматированиеString в Java с помощью классаjava.util.Formatter, который обеспечивает поддержку выравнивания и выравнивания макета.

2. Как использоватьFormatter

Помните C’sprintf? ФорматированиеString в Java очень похоже.

Методformat() классаFormatter предоставляется через статический метод из классаString. Этот метод принимает шаблонString и список аргументов для заполнения шаблона:

String greetings = String.format(
  "Hello Folks, welcome to %s !",
  "example");

В результатеString:

"Hello Folks, welcome to example !"

Шаблон - этоString, который содержит некоторый статический текст и один или несколько спецификаторов формата, которые указывают, какой аргумент должен быть помещен в определенную позицию.

В этом случаеthere’s a single format specifier %s, which gets replaced by the corresponding argument.

3. Спецификаторы формата

3.1. Общий синтаксис

Синтаксис спецификаторов формата для типовGeneral, Character, иNumeric:

%[argument_index$][flags][width][.precision]conversion

Спецификаторыargument_index, flag, width иprecision необязательны.

  • Частьargument_index представляет собой целое числоi - указывает, что здесь следует использовать аргументith из списка аргументов

  • flags - это набор символов, используемых для изменения формата вывода

  • width - положительное целое число, которое указывает минимальное количество символов, которое должно быть записано на вывод

  • precision - целое число, обычно используемое для ограничения количества символов, конкретное поведение которых зависит от преобразования.

  • является обязательной частью. Это символ, указывающий, как должен быть отформатирован аргумент. Набор допустимых преобразований для данного аргумента зависит от типа данных аргумента.

В нашем примере выше, если мы хотим указать номер аргумента явно, мы можем записать его, используя индексы аргументов1$ и2$.

Оба они являются первым и вторым аргументом соответственно:

String greetings = String.format(
  "Hello %2$s, welcome to %1$s !",
  "example",
  "Folks");

3.2. Для представленияDate/Time

%[argument_index$][flags][width]conversion

И сноваargument_index, flags иwidth необязательны.

Давайте рассмотрим пример, чтобы понять это:

@Test
public void whenFormatSpecifierForCalendar_thenGotExpected() {
    Calendar c = new GregorianCalendar(2017, 11, 10);
    String s = String.format(
      "The date is: %tm %1$te,%1$tY", c);

    assertEquals("The date is: 12 10,2017", s);
}

Здесь для каждого спецификатора формата будет использоваться 1-й аргумент, следовательно,1$. Здесь, если мы пропустимargument_index для 2-го и 3-го спецификатора формата, он попытается найти 3 аргумента, но нам нужно использовать один и тот же аргумент для всех 3 спецификаторов формата.

Так что ничего страшного, если мы не укажемargument _index для первого, но нам нужно указать его для двух других.

flag здесь состоит из двух символов. Где первый символ всегда‘t' или‘T'. Второй символ зависит от того, какая частьCalendar должна отображаться.

В нашем примере первый спецификатор форматаtm указывает месяц в формате двух цифр,te указывает день месяца, аtY указывает год в формате четырех цифр.

3.3. Спецификаторы формата без аргументов

%[flags][width]conversion

Необязательныеflags иwidth такие же, как определено в предыдущих разделах.

Требуемыйconversion - это символ илиString, указывающий содержимое, которое будет вставлено в вывод. В настоящее время можно распечатать только‘%' и новую строку‘n':

@Test
public void whenNoArguments_thenExpected() {
    String s = String.format("John scored 90%% in Fall semester");

    assertEquals("John scored 90% in Fall semester", s);
}

Внутриformat(), если мы хотим вывести‘%' - нам нужно избежать его, используя‘%%'.

4. Конверсии

Давайте теперь подробно рассмотрим синтаксис спецификатора формата, начиная сconversion. Обратите внимание, что вы можете найти все подробности вFormatter javadocs.

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

Давайте рассмотрим каждый из них на примерах.

4.1. генеральный

Используется для любого типа аргумента. Общие преобразования:

  1. ‘b’ или‘B' - для значенийBoolean

  2. ‘h’ или‘H' - дляHashCode

  3. ‘s' или‘S' - дляString, еслиnull, он печатает «null», иначеarg.toString()

Теперь попробуем отобразить значенияboolean иString, используя соответствующие преобразования:

@Test
public void givenString_whenGeneralConversion_thenConvertedString() {
    String s = String.format("The correct answer is %s", false);
    assertEquals("The correct answer is false", s);

    s = String.format("The correct answer is %b", null);
    assertEquals("The correct answer is false", s);

    s = String.format("The correct answer is %B", true);
    assertEquals("The correct answer is TRUE", s);
}

4.2. символ

Используется для основных типов, представляющих символы Юникода:char, Character, byte, Byte, short, иShort. Это преобразование также можно использовать для типовint иInteger, когдаCharacter.isValidCodePoint(int) возвращает для нихtrue.

Его можно записать как‘c’ или’C’ в зависимости от того, какой случай мы хотим.

Попробуем напечатать несколько символов:

@Test
public void givenString_whenCharConversion_thenConvertedString() {
    String s = String.format("The correct answer is %c", 'a');
    assertEquals("The correct answer is a", s);

    s = String.format("The correct answer is %c", null);
    assertEquals("The correct answer is null", s);

    s = String.format("The correct answer is %C", 'b');
    assertEquals("The correct answer is B", s);

    s = String.format("The valid unicode character: %c", 0x0400);
    assertTrue(Character.isValidCodePoint(0x0400));
    assertEquals("The valid unicode character: Ѐ", s);
}

Возьмем еще один пример недопустимого кода:

@Test(expected = IllegalFormatCodePointException.class)
public void whenIllegalCodePointForConversion_thenError() {
    String s = String.format("The valid unicode character: %c", 0x11FFFF);

    assertFalse(Character.isValidCodePoint(0x11FFFF));
    assertEquals("The valid unicode character: Ā", s);
}

4.3. Числовой - интеграл

Они используются для целочисленных типов Java:byte, Byte, short, Short, int,Integer, long, Long, иBigInteger. В этой категории есть три преобразования:

  1. ‘d' - для десятичного числа

  2. ‘o' - для восьмеричного числа

  3. ‘X' или‘x' - для шестнадцатеричного числа

Попробуем распечатать каждый из них:

@Test
public void whenNumericIntegralConversion_thenConvertedString() {
    String s = String.format("The number 25 in decimal = %d", 25);
    assertEquals("The number 25 in decimal = 25", s);

    s = String.format("The number 25 in octal = %o", 25);
    assertEquals("The number 25 in octal = 31", s);

    s = String.format("The number 25 in hexadecimal = %x", 25);
    assertEquals("The number 25 in hexadecimal = 19", s);
}

4.4. Числовой - с плавающей точкой

Используется для типов Java с плавающей запятой:float, Float, double, Double, иBigDecimal

  1. ‘e' или‘E' отформатированы как десятичное число в компьютеризированной научной нотации

  2. ‘f' в формате десятичного числа

  3. ‘g' или‘G' в зависимости от значения точности после округления, это преобразование форматируется в компьютеризированную научную нотацию или десятичный формат

Попробуем распечатать числа с плавающей запятой:

@Test
public void whenNumericFloatingConversion_thenConvertedString() {
    String s = String.format(
      "The computerized scientific format of 10000.00 "
      + "= %e", 10000.00);

    assertEquals(
      "The computerized scientific format of 10000.00 = 1.000000e+04", s);

    String s2 = String.format("The decimal format of 10.019 = %f", 10.019);
    assertEquals("The decimal format of 10.019 = 10.019000", s2);
}

4.5. Прочие преобразования

  • Date/Time - для типов Java, которые могут кодировать дату или время:long, Long, Calendar,Date иTemporalAccessor.. Для этого нам нужно использовать префикс‘t' или‘T', как мы видели ранее

  • Percent - печатает буквальный‘%' (‘%')

  • Line Separator - печатает разделитель строк, зависящий от платформы

Давайте посмотрим на простой пример:

@Test
public void whenLineSeparatorConversion_thenConvertedString() {
    String s = String.format("First Line %nSecond Line");

    assertEquals("First Line \n" + "Second Line", s);
}

5. Флаги

Флаги, как правило, используются для форматирования вывода. Принимая во внимание, что в случае даты и времени они используются для указания, какая часть даты должна отображаться, как мы видели в примере Раздела 4.

Доступно несколько флагов, список которых можно найти в документации.

Давайте посмотрим на пример флага, чтобы понять его использование. ‘-‘ используется для форматирования вывода по левому краю:

@Test
public void whenSpecifyFlag_thenGotFormattedString() {
    String s = String.format("Without left justified flag: %5d", 25);
    assertEquals("Without left justified flag:    25", s);

    s = String.format("With left justified flag: %-5d", 25);
    assertEquals("With left justified flag: 25   ", s);
}

6. точность

Для общих преобразованийprecision is just the maximum number of characters to be written to the output. Принимая во внимание, что для преобразований с плавающей точкой точность - это число цифр после радикальной точки.

Первый оператор является примером точности с числами с плавающей точкой, а второй - с общими преобразованиями:

@Test
public void whenSpecifyPrecision_thenGotExpected() {
    String s = String.format(
      "Output of 25.09878 with Precision 2: %.2f", 25.09878);

    assertEquals("Output of 25.09878 with Precision 2: 25.10", s);

    String s2 = String.format(
      "Output of general conversion type with Precision 2: %.2b", true);

    assertEquals("Output of general conversion type with Precision 2: tr", s2);
}

7. Индекс аргумента

Как упоминалось ранее,argument_index is an integer that indicates the position of the argument in the argument list. 1$ указывает первый аргумент,2$ - второй аргумент и так далее.

Кроме того, есть другой способ ссылаться на аргументы по позиции, используя флаг‘<‘ (‘<'), что означает, что аргумент из предыдущего спецификатора формата будет повторно использован. Например, эти два оператора будут производить одинаковый вывод:

@Test
public void whenSpecifyArgumentIndex_thenGotExpected() {
    Calendar c = Calendar.getInstance();
    String s = String.format("The date is: %tm %1$te,%1$tY", c);
    assertEquals("The date is: 12 10,2017", s);

    s = String.format("The date is: %tm %

8. Другие способы использованияFormatter

До сих пор мы видели использование методаformat() классаFormatter. Мы также можем создать экземплярFormatter и использовать его для вызова методаformat().

We can create an instance by passing in an Appendable, OutputStream, File or file name. Исходя из этого, форматированныйString сохраняется вAppendable,OutputStream,File соответственно.

Давайте посмотрим на пример использования его сAppendable.. Мы можем использовать его с другими таким же образом.

8.1. ИспользованиеFormatter сAppendable

Давайте создадим экземпляр StringBuildersb и создадимFormatter, используя его. Затем мы вызовемformat() для форматированияString:

@Test
public void whenCreateFormatter_thenFormatterWithAppendable() {
    StringBuilder sb = new StringBuilder();
    Formatter formatter = new Formatter(sb);
    formatter.format("I am writting to a %s Instance.", sb.getClass());

    assertEquals(
      "I am writting to a class java.lang.StringBuilder Instance.",
      sb.toString());
}

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

В этой статье мы увидели возможности форматирования, предоставляемые классомjava.util.Formatter. Мы увидели различный синтаксис, который можно использовать для форматированияString, и типы преобразования, которые можно использовать для разных типов данных.

Как обычно, код для рассмотренных нами примеров находится вover on Github.