Перетворення BigDecimal в цілий


134

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

Тепер як перетворити BigDecimal в цілий і передати його другому методу?

Чи є вихід з цього?


6
Я виправив вашу назву. Це перетворення, а не лиття.
Маркіз Лорнський

Відповіді:


209

Ви б зателефонували myBigDecimal.intValueExact()(або просто intValue()), і це навіть викине виняток, якщо ви втратите інформацію. Це повертає Int, але про це береться автобікс.


1
intValueExact()є хорошою рекомендацією; його додали в 1,5
Anon

Телефонувати intValue()небезпечно, якщо ви не на 100% зробите ставку на своє життя на те, що їх кількість знаходиться в межах Integerдіапазону.
Снексе

1
Чи має це сенс: "Integer.valueOf (myBigDecimal.intValueExact ())"?
OddDev

32

Чи можете ви гарантувати, що BigDecimalніколи не буде містити значення, яке перевищує Integer.MAX_VALUE?

Якщо так, то ось ваш код закликає intValue:

Integer.valueOf(bdValue.intValue())

Так. Я думаю, він не буде містити більше значення, ніж Integer.MAX_VALUE
Vishal

2
Немає ніяких причин робити valueOf, крім отримання об’єкта замість примітивного права?
Василь

Я б сказав, що це має бути офіційною відповіддю, оскільки згадує межі, б. запобігає автобоксингу.
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 перший, а потім конвертуйте. Це також має перевагу, що надає вам більше контролю над процесом округлення.

Тест Спока Гроуви

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, лише низький -повертається 32 біта. Зауважте, що це перетворення може втратити інформацію про загальну величину та точність цього величини BigDecimal, а також повернути результат із протилежним знаком.

Тоді ви можете або явно зателефонувати, Integer.valueOf(int)або дозволити автоматичному боксу зробити це за вас, якщо ви використовуєте досить недавню версію Java.





-4

Я виявив, що вищезгадане для мене не працює. Я стягував значення комірки з JTable, але не міг передати подвійний чи інт і т. Д. Моє рішення:

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

де рядок 0 завжди буде числом. Сподіваюсь, це допомагає комусь ще прокручуватися!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.