将 BigDecimal 转换为 Integer

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

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

有办法解决吗?

343911 次浏览

你能保证 BigDecimal永远不会包含大于 Integer.MAX_VALUE的值吗?

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

Integer.valueOf(bdValue.intValue())

下面的内容应该可以解决这个问题:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();

你可以打电话给 BigDecimal.intValue():

将此 BigDecimal 转换为 int。这种转换类似于 Java 语言规范中定义的从 double 到 short 的缩小的原语转换: BigDecimal 的任何小数部分都将被丢弃,如果产生的“ BigInteger”太大以至于无法放入 int,那么只返回低阶32位。请注意,此转换可能会丢失有关此 BigDecimal 值的整体大小和精度的信息,并返回一个符号相反的结果。

然后,您可以显式调用 Integer.valueOf(int),或者如果您使用的是最新版本的 Java,那么可以让自动装箱来完成这项工作。

您可以调用 myBigDecimal.intValueExact()(或者仅仅是 intValue()) ,如果您丢失了信息,它甚至会抛出异常。它返回一个 int,但是自动装箱处理这个问题。

你试过打电话给 BigInteger # intValue ()吗?

DR

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

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

推理

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

  • BigDecimal可能有一个非零的小数部分吗?
  • BigDecimal可能不适合 Integer范围?
  • 您希望非零小数部分是圆形的还是截断的?
  • 您希望非零小数部分圆整吗?

如果你对前两个问题的回答是否定的,你可以像其他人建议的那样使用 BigDecimal.intValueExact(),当意想不到的事情发生时让它爆炸。

如果你对问题2没有100% 的信心,那么 intValue()就是 一直都是错误的答案。

让它变得更好

让我们在其他答案的基础上使用以下假设。

  • 我们可以接受失去精度和截断值,因为这就是 intValueExact()和自动装箱所做的
  • BigDecimal大于 Integer范围时,我们希望抛出一个异常,因为除非您有非常特殊的换行需求,否则任何其他操作都将是疯狂的。

考虑到这些参数,如果我们的小数部分是非零的,那么当我们不希望 intValueExact()抛出异常时,intValueExact()会抛出异常。另一方面,如果我们的 BigDecimal太大,intValue()不会在应该抛出异常时抛出异常。

为了获得两个世界的最佳结果,首先圆满完成 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()
}

我发现上述方法对我不起作用。我从 JTable 中提取了一个单元格值,但不能强制转换为 double 或 int 等。我的解决办法是:

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

其中行0始终是一个数字。希望这对仍在滚动的人有帮助!