Почему DecimalFormat ". #" И "0. #" имеют разные результаты в 23.0?

Почему java.text.DecimalFormat оценивает следующие результаты:

new DecimalFormat("0.#").format(23.0)        // result: "23"

new DecimalFormat(".#").format(23.0)         // result: "23.0"

Я ожидал, что результат будет 23 в обоих случаях, потому что специальный символ # опускает нули. Как главный символ 0 влияет на часть дроби? (Пробовал, чтобы соответствовать/понимать его с BNF, указанным в javadoc, но не смог этого сделать.)

Ответ 1

Второй формат кажется недействительным в соответствии с JavaDoc, но каким-то образом он все равно разбирает без ошибок.

 Pattern:
         PositivePattern
         PositivePattern ; NegativePattern
 PositivePattern:
         Prefixopt Number Suffixopt
 NegativePattern:
         Prefixopt Number Suffixopt
 Prefix:
         any Unicode characters except \uFFFE, \uFFFF, and special characters
 Suffix:
         any Unicode characters except \uFFFE, \uFFFF, and special characters
 Number:
         Integer Exponentopt
         Integer . Fraction Exponentopt
 Integer:
         MinimumInteger
         #
         # Integer
         # , Integer
 MinimumInteger:
         0
         0 MinimumInteger
         0 , MinimumInteger
 Fraction:
         MinimumFractionopt OptionalFractionopt
 MinimumFraction:
         0 MinimumFractionopt
 OptionalFraction:
         # OptionalFractionopt
 Exponent:
         E MinimumExponent
 MinimumExponent:
         0 MinimumExponentopt

В этом случае я ожидаю, что поведение форматирования будет undefined. То есть, это может порождать любую старую вещь, и мы не можем полагаться на то, что она является последовательной или значимой. Итак, я не знаю, почему вы получаете 23.0, но можете предположить, что это бессмыслица, которую вы должны избегать в своем коде.

Update: Я только что запустил отладчик через библиотеку Java 7 DecimalFormat. Код не только явно указывает, что разрешен ". #", Там есть комментарий (java.text.DecimalFormat: 2582-2593), который говорит, что он разрешен, и реализацию, которая позволяет это (строка 2597). Это, по-видимому, нарушает документированный BNF для шаблона.

Учитывая, что это не документированное поведение, вы действительно не должны полагаться на него, поскольку оно может изменяться между версиями Java или даже реализацией библиотек.

Ответ 2

Следующий комментарий источника объясняет довольно неинтуитивную обработку ".#". Строки 3383-3385 ​​в моем DecimalFormat.java файле (JDK 8) имеют следующий комментарий:

// Handle patterns with no '0' pattern character. These patterns
// are legal, but must be interpreted.  "##.###" -> "#0.###".
// ".###" -> ".0##".

Похоже, разработчики решили интерпретировать ".#" как ".0##", а не то, что вы ожидали ("0.#").