Converting BigDecimal to Integer

328,915

Solution 1

You would call myBigDecimal.intValueExact() (or just intValue()) and it will even throw an exception if you would lose information. That returns an int but autoboxing takes care of that.

Solution 2

Can you guarantee that the BigDecimal will never contain a value larger than Integer.MAX_VALUE?

If yes, then here's your code calling intValue:

Integer.valueOf(bdValue.intValue())

Solution 3

TL;DR

Use one of these for universal conversion needs

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

Reasoning

The answer depends on what the requirements are and how you answer these question.

  • Will the BigDecimal potentially have a non-zero fractional part?
  • Will the BigDecimal potentially not fit into the Integer range?
  • Would you like non-zero fractional parts rounded or truncated?
  • How would you like non-zero fractional parts rounded?

If you answered no to the first 2 questions, you could just use BigDecimal.intValueExact() as others have suggested and let it blow up when something unexpected happens.

If you are not absolutely 100% confident about question number 2, then intValue() is always the wrong answer.

Making it better

Let's use the following assumptions based on the other answers.

  • We are okay with losing precision and truncating the value because that's what intValueExact() and auto-boxing do
  • We want an exception thrown when the BigDecimal is larger than the Integer range because anything else would be crazy unless you have a very specific need for the wrap around that happens when you drop the high-order bits.

Given those params, intValueExact() throws an exception when we don't want it to if our fractional part is non-zero. On the other hand, intValue() doesn't throw an exception when it should if our BigDecimal is too large.

To get the best of both worlds, round off the BigDecimal first, then convert. This also has the benefit of giving you more control over the rounding process.

Spock 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()
}

Solution 4

Well, you could call BigDecimal.intValue():

Converts this BigDecimal to an int. This conversion is analogous to a narrowing primitive conversion from double to short as defined in the Java Language Specification: any fractional part of this BigDecimal will be discarded, and if the resulting "BigInteger" is too big to fit in an int, only the low-order 32 bits are returned. Note that this conversion can lose information about the overall magnitude and precision of this BigDecimal value as well as return a result with the opposite sign.

You can then either explicitly call Integer.valueOf(int) or let auto-boxing do it for you if you're using a sufficiently recent version of Java.

Solution 5

Following should do the trick:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();
Share:
328,915
Vishal
Author by

Vishal

SDE 2 @Amazon

Updated on April 30, 2020

Comments

  • Vishal
    Vishal about 4 years

    I have Hibernate method which returns me a BigDecimal. I have another API method to which I need to pass that number but it accepts Integer as parameter. I cannot change return types or variable types of both methods.

    Now how to convert the BigDecimal into Integer and pass it to second method?

    Is there a way out of this?

  • Vishal
    Vishal over 13 years
    Yes. I guess it will not contain larger value than Integer.MAX_VALUE
  • Anon
    Anon over 13 years
    intValueExact() is a good recommendation; it was added in 1.5
  • Basil
    Basil almost 10 years
    There's no reason to do the valueOf other than to get an Object instead of a primitive right?
  • Snekse
    Snekse about 9 years
    Calling intValue() is dangerous unless you are 100% bet your life on it positive that the number is within the Integer range.
  • ledlogic
    ledlogic almost 9 years
    I would say this should be the official answer because a. mentions the limits, b. prevents autoboxing.
  • OddDev
    OddDev over 8 years
    Does this makes sense: "Integer.valueOf(myBigDecimal.intValueExact())"?