为什么 DecimalFormat ".#" 和 "0.#" 在 23.0 上有不同的结果?

Why does DecimalFormat ".#" and "0.#" have different results on 23.0?

为什么 java.text.DecimalFormat 评估以下结果:

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

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

我本以为这两种情况的结果都是 23,因为特殊字符 # 省略了零。前导特殊字符 0 如何影响小数部分? (尝试 match/understand 使用 javadoc 中给出的 BNF,但失败了。)

根据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

在这种情况下,我希望格式化程序的行为是未定义的。也就是说,它可能会产生任何旧的东西,我们不能依赖它以任何方式保持一致或有意义。所以,我不知道你为什么得到 23.0,但你可以假设你应该在你的代码中避免它是无稽之谈。

更新: 我只是 运行 一个通过 Java 7 的 DecimalFormat 库的调试器。该代码不仅明确指出“.#”是允许的,其中还有一条注释 (java.text.DecimalFormat:2582-2593) 表明它是允许的,并且还有一个允许它的实现(第 2597 行)。这似乎违反了该模式的文档化 BNF。

鉴于这不是记录在案的行为,您真的不应该依赖它,因为它可能会在 Java 版本甚至库实现之间发生变化。

以下源评论解释了 ".#" 的相当不直观的处理。我的 DecimalFormat.java 文件 (JDK 8) 中的第 3383-3385 行有以下注释:

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

开发人员似乎选择将 ".#" 解释为 ".0##",而不是您所期望的 ("0.#")。