Convertir BigDecimal a Integer

134

Tengo el método Hibernate que me devuelve un BigDecimal. Tengo otro método API al que necesito pasar ese número, pero acepta Integer como parámetro. No puedo cambiar los tipos de retorno o los tipos de variables de ambos métodos.

Ahora, ¿cómo convertir BigDecimal en Integer y pasarlo al segundo método?

¿Hay alguna forma de salir de esto?

Vishal
fuente
66
Corregí tu título. Esto es conversión, no fundición.
Marqués de Lorne

Respuestas:

209

Llamaría myBigDecimal.intValueExact()(o simplemente intValue()) e incluso arrojará una excepción si pierde información. Eso devuelve un int pero el autoboxing se encarga de eso.

willcodejavaforfood
fuente
1
intValueExact()es una buena recomendación fue agregado en 1.5
Anon
Llamar intValue()es peligroso a menos que esté 100% seguro de que su vida es segura de que el número está dentro del Integerrango.
Snekse
1
¿Tiene sentido esto: "Integer.valueOf (myBigDecimal.intValueExact ())"?
OddDev
32

¿Puede garantizar que BigDecimalnunca contendrá un valor mayor que Integer.MAX_VALUE?

En caso afirmativo, aquí está su código de llamada intValue:

Integer.valueOf(bdValue.intValue())
Luego
fuente
Si. Supongo que no contendrá un valor mayor que Integer.MAX_VALUE
Vishal
2
No hay ninguna razón para hacer el valor de otra cosa que no sea obtener un objeto en lugar de un derecho primitivo?
Basil
Yo diría que esta debería ser la respuesta oficial porque a. menciona los límites, b. evita el autoboxing.
ledlogic
22

TL; DR

Utilice uno de estos para las necesidades de conversión universal.

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

Razonamiento

La respuesta depende de cuáles son los requisitos y cómo responde a estas preguntas.

  • ¿Tendrá BigDecimalpotencialmente una parte fraccionaria distinta de cero?
  • ¿ BigDecimalPotencialmente no encajará en el Integerrango?
  • ¿Desea partes fraccionarias distintas de cero redondeadas o truncadas?
  • ¿Cómo le gustaría redondear las partes fraccionarias distintas de cero?

Si respondió no a las 2 primeras preguntas, puede usarlas BigDecimal.intValueExact()como otros han sugerido y dejar que explote cuando ocurra algo inesperado.

Si no está 100% seguro de la pregunta número 2, entonces siempreintValue() es la respuesta incorrecta.

Haciéndolo mejor

Usemos los siguientes supuestos basados ​​en las otras respuestas.

  • Estamos de acuerdo con perder precisión y truncar el valor porque eso es lo que hacen intValueExact()y el auto-boxeo
  • Queremos que se produzca una excepción cuando BigDecimalsea ​​mayor que el Integerrango porque cualquier otra cosa sería una locura a menos que tenga una necesidad muy específica de la envoltura que ocurre cuando suelta los bits de alto orden.

Dados esos parámetros, intValueExact()arroja una excepción cuando no queremos que nuestra parte fraccional sea distinta de cero. Por otro lado, intValue()no arroja una excepción cuando debería si nuestro BigDecimales demasiado grande.

Para obtener lo mejor de ambos mundos, completa el BigDecimal primero y luego convierte. Esto también tiene el beneficio de darle más control sobre el proceso de redondeo.

Prueba de 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()
}
Snekse
fuente
18

Bueno, puedes llamar BigDecimal.intValue():

Convierte este BigDecimal en un int. Esta conversión es análoga a una conversión primitiva de estrechamiento de doble a corto como se define en la Especificación del lenguaje Java: cualquier parte fraccionaria de este BigDecimal será descartada, y si el "BigInteger" resultante es demasiado grande para caber en un int, solo el bajo -orden 32 bits son devueltos. Tenga en cuenta que esta conversión puede perder información sobre la magnitud general y la precisión de este valor BigDecimal, así como devolver un resultado con el signo opuesto.

Luego puede llamar explícitamente Integer.valueOf(int)o dejar que el auto-boxeo lo haga por usted si está utilizando una versión suficientemente reciente de Java.

Jon Skeet
fuente
9

Lo siguiente debería hacer el truco:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();
Gareth Davis
fuente
-4

Descubrí que lo anterior no funcionó para mí. Estaba extrayendo un valor de celda de una JTable pero no podía convertir a doble o int, etc. Mi solución:

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

donde la fila 0 siempre sería un número. ¡Espero que esto ayude a cualquiera que todavía se esté desplazando!

Colmena
fuente