将BigDecimal转换为整数


134

我有Hibernate方法,它返回了一个BigDecimal。我有另一个API方法,我需要将该数字传递给它,但是它接受Integer作为参数。我不能更改两种方法的返回类型或变量类型。

现在如何将BigDecimal转换为Integer并将其传递给第二种方法?

有没有解决的办法?


6
我更正了你的头衔。这是转换,不是强制转换。
罗恩侯爵,2010年

Answers:


209

您将致电myBigDecimal.intValueExact()(或仅致电intValue()),如果您丢失了信息,它甚至会引发异常。返回一个int,但是自动装箱会解决这个问题。


1
intValueExact()是一个很好的建议;它是在1.5加入
匿名

intValue()除非您百分百地肯定自己的电话号码在该Integer范围内,否则打电话是危险的。
Snekse

1
这是否有意义:“ Integer.valueOf(myBigDecimal.intValueExact())”?
OddDev

32

您可以保证BigDecimal绝对不会包含大于的值Integer.MAX_VALUE吗?

如果是,那么这里是您的代码调用intValue

Integer.valueOf(bdValue.intValue())

是。我猜它不会包含比Integer.MAX_VALUE大的值
Vishal 2010年

2
除了获取Object而不是原始权限外,没有其他理由要做valueOf吗?
罗勒

我想说这应该是官方的答案,因为 提到限制,b。防止自动装箱。
ledlogic

22

TL; DR

使用其中之一满足通用转换需求

//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8    
bigDecimal.toBigInteger().intValueExact()

推理

答案取决于要求是什么以及如何回答这些问题。

  • BigDecimal潜在的分数部分将为非零吗?
  • 请问BigDecimal可能不适合的Integer范围是多少?
  • 您想要舍入或截断非零小数部分吗?
  • 您如何希望将非零小数部分四舍五入?

如果您对前两个问题的回答为“否”,则可以BigDecimal.intValueExact()按照他人的建议使用,并在发生意外情况时将其炸毁。

如果你不是绝对100%的信心问题编号2,然后intValue()一直错误的答案。

变得更好

让我们基于其他答案使用以下假设。

  • 我们可以保留精度并舍弃值,因为这就是intValueExact()自动装箱
  • 我们希望在BigDecimal大于Integer范围时引发异常,因为除非您有特殊的需要,即当您丢弃高位时发生回绕,否则任何其他事情都会令人发疯。

给定这些参数,intValueExact()如果我们不希望小数部分为非零,则抛出异常。另一方面,intValue()如果我们BigDecimal太大,则不应该抛出异常。

要获得两全其美,BigDecimal请先将其四舍五入,然后再进行转换。这还具有使您对舍入过程有更多控制的好处。

Spock Groovy测试

void 'test BigDecimal rounding'() {
    given:
    BigDecimal decimal = new BigDecimal(Integer.MAX_VALUE - 1.99)
    BigDecimal hugeDecimal = new BigDecimal(Integer.MAX_VALUE + 1.99)
    BigDecimal reallyHuge = new BigDecimal("10000000000000000000000000000000000000000000000")
    String decimalAsBigIntString = decimal.toBigInteger().toString()
    String hugeDecimalAsBigIntString = hugeDecimal.toBigInteger().toString()
    String reallyHugeAsBigIntString = reallyHuge.toBigInteger().toString()

    expect: 'decimals that can be truncated within Integer range to do so without exception'
    //GOOD: Truncates without exception
    '' + decimal.intValue() == decimalAsBigIntString
    //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information
    // decimal.intValueExact() == decimalAsBigIntString
    //GOOD: Truncates without exception
    '' + decimal.setScale(0, RoundingMode.DOWN).intValueExact() == decimalAsBigIntString

    and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception'
    //BAD: hugeDecimal.intValue() is -2147483648 instead of 2147483648
    //'' + hugeDecimal.intValue() == hugeDecimalAsBigIntString
    //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information
    //'' + hugeDecimal.intValueExact() == hugeDecimalAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + hugeDecimal.setScale(0, RoundingMode.DOWN).intValueExact() == hugeDecimalAsBigIntString

    and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception'
    //BAD: hugeDecimal.intValue() is 0
    //'' + reallyHuge.intValue() == reallyHugeAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + reallyHuge.intValueExact() == reallyHugeAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + reallyHuge.setScale(0, RoundingMode.DOWN).intValueExact() == reallyHugeAsBigIntString

    and: 'if using Java 8, BigInteger has intValueExact() just like BigDecimal'
    //decimal.toBigInteger().intValueExact() == decimal.setScale(0, RoundingMode.DOWN).intValueExact()
}

18

好吧,您可以致电BigDecimal.intValue()

将此BigDecimal转换为int。此转换类似于Java语言规范中定义的从double到short的原始缩元转换:此BigDecimal的任何小数部分都将被丢弃,并且如果结果“ BigInteger”太大而无法容纳int,则仅将低位-返回32位。请注意,此转换会丢失有关此BigDecimal值的整体大小和精度的信息,并返回带有相反符号的结果。

然后Integer.valueOf(int),如果您使用的是Java的最新版本,则可以显式调用或让自动装箱完成。





-4

我发现上述方法对我不起作用。我正在从JTable中提取一个单元格值,但无法转换为double或int等。我的解决方案:

Object obj = getTable().getValueAt(row, 0);

其中第0行将始终是数字。希望这可以帮助仍然滚动的任何人!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.