BigDecimal 语言环境特定解析 - Wicket 的 BigDecimalConverter 和 java.math.BigDecimal 之间不一致

发布于 2024-12-13 20:11:33 字数 507 浏览 4 评论 0原文

当从字符串中解析带有小数分隔符的数字时,Wicket 的 BigDecimalConverter 的行为与 BigDecimal 的 (String val) 构造函数不同。

让我们尝试使用美国语言环境解析以逗号作为小数分隔符的数字。 (顺便说一句,我使用的是 Wicket 1.4.14。)


new BigDecimalConverter().convertToObject("1,3", Locale.US)
返回 13



Locale.setDefault(Locale.US);
new BigDecimal("1,3")  

抛出 NumberFormatException


在这种情况下,为什么 BigDecimalConverter 的行为与 BigDecimal 不同?数字“1,3”对于美国语言环境没有意义。

When it comes to parsing numbers with decimal separators from string, Wicket's BigDecimalConverter behaves differently than BigDecimal's (String val) constructor.

Let's try to parse a number with comma as the decimal separator using US locale. (I'm using Wicket 1.4.14 BTW.)


new BigDecimalConverter().convertToObject("1,3", Locale.US)
returns 13,


but


Locale.setDefault(Locale.US);
new BigDecimal("1,3")  

throws NumberFormatException.


Why doesn't BigDecimalConverter behave the same way as BigDecimal in this case? The number "1,3" doesn't make sense for the US locale.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浅唱々樱花落 2024-12-20 20:11:33

BigDecimal 类在输入上实现自己的验证算法,该算法会抛出 NumberFormatException。

BigDecimalConverter1,3 解析为 13 的原因是它在幕后使用原始 DecimalFormat 。在 AbstractNumberConverter.parse()getNumberFormat(locale)parse() 方法组合归结为以下代码片段,将 Wicket 排除在等式之外:

NumberFormat format = NumberFormat.getInstance(Locale.US);
format.setParseBigDecimal(true);
BigDecimal bd = format.parseObject("1,3");
System.out.println(bd.toString()); // Prints 13 !

UPDATE
DecimalFormat 忽略 , 字符的原因是它在美国语言环境的 DecimalFormatSymbols 中被定义为分组分隔符。
这是允许的,并且是合法的,就像在 1,300.5 中一样。

如果您想避免将 1,3 转换为 13,并抛出无效的格式转换异常,您可以重写 BigDecimalConverter.getNumberFormat(Locale) 为了将 DecimalFormat 修改为不使用分组,请使用不同的分组符号,或使用更具限制性的模式。例如:

TextField<BigDecimal> text = new TextField<BigDecimal>(id, model){
    @Override
    public IConverter getConverter(Class<?> type) {
        return new BigDecimalConverter() {
            @Override
            public NumberFormat getNumberFormat(Locale locale) {
                NumberFormat format = super.getNumberFormat(locale);
                format.setGroupingUsed(false);
                return format;
            }
        };
    }
};
text.setType(BigDecimal.class);

注意:谨慎使用上面的示例,为转换器创建一个类,这样它就不会在每次调用 getConverter() 时实例化,并且不要修改NumberFormat实例BigDecimalConverter.getNumberFormat()返回,它可能是一个全局共享实例。

只是补充一下,这是忽略 , 字符作为组分隔符的确切代码:DecimalFormat.subparse() 第 1522 行分支。输入 1,3 时,逗号将被忽略,为 isGroupingUsed() true。

The BigDecimal class implements its own validation algorithm on the input, which is throwing the NumberFormatException.

The reason why BigDecimalConverter is parsing 1,3 as 13 is that it is using a raw DecimalFormat behind the scenes. In AbstractNumberConverter.parse(), the getNumberFormat(locale) and parse() methods combination boils down to the following snippet, that takes Wicket out of the equation:

NumberFormat format = NumberFormat.getInstance(Locale.US);
format.setParseBigDecimal(true);
BigDecimal bd = format.parseObject("1,3");
System.out.println(bd.toString()); // Prints 13 !

UPDATE
The reason why DecimalFormat is ignoring the , character is because it is defined as the grouping separator in the DecimalFormatSymbols for the US locale.
It is permitted, and legal as it would be in 1,300.5.

In case you want to avoid converting 1,3 to 13, and throwing a invalid format conversion exception, you could override BigDecimalConverter.getNumberFormat(Locale) in order to modify the DecimalFormat to not use grouping, use a different grouping symbol, or use a more restrictive pattern. For instance:

TextField<BigDecimal> text = new TextField<BigDecimal>(id, model){
    @Override
    public IConverter getConverter(Class<?> type) {
        return new BigDecimalConverter() {
            @Override
            public NumberFormat getNumberFormat(Locale locale) {
                NumberFormat format = super.getNumberFormat(locale);
                format.setGroupingUsed(false);
                return format;
            }
        };
    }
};
text.setType(BigDecimal.class);

Note: Use the above example with caution, create a class for the Converter so it doesn't get instantiated at each call of getConverter() and don't modify the NumberFormat instance BigDecimalConverter.getNumberFormat() returns, it might be a global shared instance.

Just to add, this is the exact piece of code that's ignoring the , character for being a group separator: DecimalFormat.subparse() branch in line 1522. With input of 1,3, the comma is ignored, being isGroupingUsed() true.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文