Преобразование BigDecimal в целое число


135

У меня есть метод Hibernate, который возвращает мне BigDecimal. У меня есть другой метод API, которому нужно передать это число, но он принимает целое число в качестве параметра. Я не могу изменить возвращаемые типы или типы переменных обоих методов.

Как теперь преобразовать BigDecimal в Integer и передать его второму методу?

Есть ли выход из этого?


6
Я исправил ваш заголовок. Это преобразование, а не кастинг.
Маркиз Лорн,

Ответы:


209

Вы бы позвонили myBigDecimal.intValueExact()(или просто intValue()), и он даже вызовет исключение, если вы потеряете информацию. Это возвращает int, но автобоксинг позаботится об этом.


1
intValueExact()хорошая рекомендация; это было добавлено в 1.5
Anon

Колл intValue()опасен, если вы не ставите на 100% свою жизнь и уверены, что число находится в пределах Integerдиапазона.
Snekse

1
Имеет ли это смысл: «Integer.valueOf (myBigDecimal.intValueExact ())»?
OddDev

32

Можете ли вы гарантировать, что BigDecimalникогда не будет содержать значение больше чем Integer.MAX_VALUE?

Если да, то вот ваш код вызова intValue:

Integer.valueOf(bdValue.intValue())

Да. Я предполагаю, что он не будет содержать большего значения, чем Integer.MAX_VALUE
Vishal

2
Нет никакой причины использовать valueOf, кроме как получить объект вместо примитива, верно?
Basil

Я бы сказал, что это должен быть официальный ответ, потому что файл. упоминает пределы, b. предотвращает автобокс.
ledlogic

22

TL; DR

Используйте один из них для универсального преобразования

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

аргументация

Ответ зависит от требований и того, как вы ответите на эти вопросы.

  • Будет ли BigDecimalпотенциально иметь ненулевую дробную часть?
  • BigDecimalНе впишется ли потенциально в Integerдиапазон?
  • Хотите округлить или усечь ненулевые дробные части?
  • Как бы вы хотели округлить ненулевые дробные части?

Если вы ответили «нет» на первые 2 вопроса, вы можете просто использовать, BigDecimal.intValueExact()как предлагали другие, и позволить этому взорваться, когда произойдет что-то неожиданное.

Если вы не на 100% уверены в вопросе номер 2, то intValue()это всегда неправильный ответ.

Делая это лучше

Давайте использовать следующие предположения, основанные на других ответах.

  • Мы не против потери точности и усечения значения, потому что это то, что intValueExact()делает автобокс.
  • Мы хотим, чтобы исключение генерировалось, когда BigDecimalбольше, чем Integerдиапазон, потому что все остальное было бы сумасшедшим, если у вас нет особой потребности в обертке, которая происходит, когда вы отбрасываете старшие биты.

Учитывая эти параметры, intValueExact()выдает исключение, если мы этого не хотим, если наша дробная часть не равна нулю. С другой стороны, intValue()не генерирует исключение, если должно, если наш BigDecimalслишком велик.

Чтобы получить лучшее из обоих миров, округлите BigDecimalпервый, а затем конвертируйте. Это также дает вам больше контроля над процессом округления.

Спок Groovy Test

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: любая дробная часть этого BigDecimal будет отброшена, и если результирующий «BigInteger» окажется слишком большим, чтобы поместиться в int, только младший -order 32 бита возвращаются. Обратите внимание, что это преобразование может потерять информацию об общей величине и точности этого BigDecimal значения, а также вернуть результат с противоположным знаком.

Затем вы можете либо явно вызвать, Integer.valueOf(int)либо позволить автоматической упаковке делать это за вас, если вы используете достаточно последнюю версию Java.





-4

Я обнаружил, что это не помогло мне. Я извлекал значение ячейки из JTable, но не мог преобразовать его в double или int и т. Д. Мое решение:

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

где строка 0 всегда будет числом. Надеюсь, это поможет всем, кто все еще прокручивает!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.