首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ResultSet::getBigDecimal为joda-money抛出规模异常

ResultSet::getBigDecimal为joda-money抛出规模异常
EN

Stack Overflow用户
提问于 2014-05-11 21:53:39
回答 3查看 2.7K关注 0票数 5

试图从从Money数据库读取的BigDecimal创建Joda货币MySQL对象会引发错误。

此代码:

代码语言:javascript
复制
PreparedStatement p_stmt = ...;
ResultSet results = ...;
Money amount = Money.of(CurrencyUnit.USD, results.getBigDecimal("amount"));

抛出这个:

代码语言:javascript
复制
java.lang.ArithmeticException: Scale of amount 1.0000 is greater than the scale of the currency USD
    at org.joda.money.Money.of(Money.java:74)
    at core.DB.getMoney(DB.java:4821)

实际上,我通过添加四舍五入解决了错误:

代码语言:javascript
复制
Money amount = Money.of(CurrencyUnit.USD, results.getBigDecimal("amount"), RoundingMode.HALF_UP);

但是,我对这个解决方案持怀疑态度。这是最好的吗?

我使用DECIMAL(19,4)按照this SO answer在DB上存储货币值。老实说,我有点搞不懂为什么那里的答案要求在DB上精确计算4位小数,但我倾向于相信高价值的答案,我想他们知道他们在说什么,我会后悔不听从他们的建议。然而,尤达-货币不喜欢4小数位的精度与美国货币。也许DECIMAL(19,4)是一个国际标准,他们需要小数点4位的精度?不确定..。

为了使问题简洁:

  1. RoundingMode.HALF_UP是解决此错误的理想解决方案吗?
  2. 我是否应该将MySQL DB的精度从DECIMAL(19,4)更改为DECIMAL(19,2)
  3. 有没有办法改变Joda-Money的精确性?如果是,我应该吗?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-08-01 00:21:05

Joda Money和BigDecimal为每种货币类型定义了一个“规模”。

比例尺是否定的。货币使用的小数位数。

因此,美元的刻度是2(小数位后的两个小数位)。

如果您试图从一个有两个以上小数位的源实例化美元货币的货币实例,那么您将得到一个比例尺错误。例如:

代码语言:javascript
复制
20.99 is fine
20.991 throws an error.

其他货币允许不同的小数位数。

根据文档,如果实际需要舍入,RoundMode.UNNECESSARY实际上会抛出异常。

假设美元是2位,那么小数位是2位。

使用:

代码语言:javascript
复制
Money money = Money.of(CurrencyUnit.USD, value, RoundingMode.UNNECESSARY);

值:

代码语言:javascript
复制
1.20 - works fine
1.200 - works fine as whilst extra digit rounding isn't necessary.
1.201 - throws an exception as rounding is necessary

四舍五入和金钱总是一个问题。我的方法是在db中存储正确的比例尺。

如果是美元,那么小数点(19,2)

使用RoundingMode.HALF_UP

做乘法除法时要小心。在除法之前做乘法会减少四舍五入的问题。如果你在做算术的时候转一圈,你就会没事的。

票数 3
EN

Stack Overflow用户

发布于 2014-05-30 17:17:12

是的,不是个好办法。你代表的是钱,所以你不能把钱收起来,放几分钱。)

问题是,CurrencyUnit.USD的数字数为2,例如: 1.45,而来自DB的数字大约是1.45343,这可能导致了规模上的差异。试着用BigMoney而不是金钱来代表金钱。

代码语言:javascript
复制
BigMoney amount = BigMoney .of(CurrencyUnit.USD, results.getBigDecimal("amount"));
票数 1
EN

Stack Overflow用户

发布于 2016-10-25 20:43:27

有同样的问题,并通过添加不必要的舍入模式来解决:

代码语言:javascript
复制
    @Test(dataProvider = "moneyValueProvider")
    public void testMoneyFromFloat(String currency, Float value) {
        CurrencyUnit cu = CurrencyUnit.of(currency);
        //Double dVal = Double.valueOf(value.toString());
        BigDecimal bigDecimal = new BigDecimal(value.toString());
        Money money = Money.of(cu, bigDecimal, RoundingMode.UNNECESSARY);
        Assert.assertNotNull(money);
        Assert.assertEquals(bigDecimal.doubleValue(), money.getAmount().doubleValue());
    }

    @DataProvider
    public static Object[][] moneyValueProvider() {
        return new Object[][] {
                    {"GBP", 22.5f},
                    {"GBP", 57.8f},
                    {"JPY", 15000.0f}

    };
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23598360

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档