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

Posted

技术标签:

【中文标题】为啥 DecimalFormat ".#" 和 "0.#" 在 23.0 上有不同的结果?【英文标题】:Why does DecimalFormat ".#" and "0.#" have different results on 23.0?为什么 DecimalFormat ".#" 和 "0.#" 在 23.0 上有不同的结果? 【发布时间】:2016-03-22 15:17:42 【问题描述】:

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

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

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

在这两种情况下,我都希望结果是 23,因为特殊字符 # 省略了零。前导特殊字符0 如何影响小数部分? (试图用 javadoc 中给出的 BNF 来匹配/理解它,但没有这样做。)

【问题讨论】:

我想知道".#"是否是一个有效的格式,如果它不应该是#.#,这也会导致23 @Tom: DecimalFormat(".0") 也可以。在 javadoc 中没有看到任何禁止“.#”之类的内容。 “在 javadoc 中没有看到任何禁止“.#”之类的东西的内容 我也没有,但这并不意味着代码可以正确处理这个问题。当.#.0 无效并且“回退”只打印数字时,DecimalFormat(".0") 的工作可能是巧合,因为它会产生相同的字符串 ("23.0")。但同样,这只是一个猜测。 标题说 15,示例代码使用 23。:) 我的错 :) 谢谢@Bathsheba! 【参考方案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

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

更新: 我刚刚通过 Java 7 的 DecimalFormat 库运行了一个调试器。该代码不仅明确表示允许使用“.#”,其中还有一条注释 (java.text.DecimalFormat:2582-2593) 表明它是允许的,以及一个允许它的实现(第 2597 行)。这似乎违反了该模式的记录 BNF。

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

【讨论】:

【参考方案2】:

以下源注释解释了对".#" 的相当不直观的处理。我的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.#")。

【讨论】:

我只是在查看 DecimalFormat 的源代码并看到了这个。 我已经在我的回答中记录了这一点,但我有不同的行号给你。我想知道是什么导致了这种差异?您还没有提到您在此处引用的 java 版本。您能否为了清楚起见添加它,因为它可能是负责任的? 我使用的是 JDK 8,这就是区别。

以上是关于为啥 DecimalFormat ".#" 和 "0.#" 在 23.0 上有不同的结果?的主要内容,如果未能解决你的问题,请参考以下文章

DecimalFormat 解析数字错误。为啥?

DecimalFormat("0.0") 返回以逗号而不是点作为分隔符的数据[重复]

DecimalFormat 为负双精度输入返回“?”而不是“-”

DecimalFormat 子模式边界无法正常工作

使用 DecimalFormat 删除最后三个零

DecimalFormat格式化输出带小数的数字类型