143

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

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

有没有办法解决这个问题?

4

8 回答 8

224

你会打电话myBigDecimal.intValueExact()(或只是intValue()),如果你会丢失信息,它甚至会抛出异常。这会返回一个 int 但自动装箱会处理这个问题。

于 2010-10-28T14:01:37.753 回答
34

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

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

Integer.valueOf(bdValue.intValue())
于 2010-10-28T13:59:33.427 回答
25

TL;博士

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

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

推理

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

  • 可能会有BigDecimal一个非零的小数部分吗?
  • BigDecimal可能不适合该Integer范围吗?
  • 您想要舍入或截断非零小数部分吗?
  • 您希望如何舍入非零小数部分?

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

如果您对第 2 个问题不是绝对 100%有信心,那么答案总是错误的intValue()

让它变得更好

让我们根据其他答案使用以下假设。

  • 我们可以接受丢失精度和截断值,因为这就是intValueExact()自动装箱的作用
  • BigDecimal我们希望在大于范围时抛出异常,Integer因为除非您对丢弃高位位时发生的回绕有非常特殊的需求,否则其他任何事情都会很疯狂。

给定这些参数,intValueExact()如果我们的小数部分不为零,则在我们不希望它发生时抛出异常。另一方面,如果 our太大,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()
}
于 2015-03-11T18:12:29.697 回答
20

好吧,你可以打电话BigDecimal.intValue()

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

Integer.valueOf(int)然后,如果您使用的是足够新的 Java 版本,则可以显式调用或让自动装箱为您执行此操作。

于 2010-10-28T14:01:05.050 回答
9

以下应该可以解决问题:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();
于 2010-10-28T14:00:06.973 回答
1

您是否尝试过调用BigInteger#intValue()

于 2010-10-28T14:02:17.890 回答
0

请参见BigDecimal#intValue()

于 2010-10-28T14:00:03.567 回答
-4

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

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

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

于 2016-04-29T21:18:37.087 回答