2010-10-28 34 views
102

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

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

¿Hay alguna forma de salir de esto?

+4

Corregí tu título. Esta es * conversión, * no * fundición. * – EJP

Respuesta

162

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

+1

'intValueExact()' es una buena recomendación; se agregó en 1.5 – Anon

+0

Llamar 'intValue()' es peligroso a menos que esté 100% seguro de que su vida en ella es positiva, y que el número está dentro del rango 'Entero '. – Snekse

+1

¿Tiene esto sentido: "Integer.valueOf (myBigDecimal.intValueExact())"? – OddDev

29

¿Puede garantizar que el BigDecimal nunca contendrá un valor mayor que Integer.MAX_VALUE?

Si es así, entonces aquí es su código de llamada intValue:

Integer.valueOf(bdValue.intValue()) 
+0

Sí. Supongo que no contendrá un valor mayor que Integer.MAX_VALUE – Vishal

+1

No hay ninguna razón para hacer el valor de otro que no sea para obtener un objeto en lugar de un primitivo ¿no? – Basil

+0

Diría que esta debería ser la respuesta oficial porque a. menciona los límites, b. previene el autoboxing – ledlogic

5

Siguiendo debe hacer el truco:

BigDecimal d = new BigDecimal(10); 
int i = d.intValue(); 
13

Bueno, se podría 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 -ordenador de 32 bits se devuelven. Tenga en cuenta que esta conversión puede perder información sobre la magnitud y precisión generales de este valor de BigDecimal, así como devolver un resultado con el signo opuesto.

A continuación, puede llamar explícitamente Integer.valueOf(int) o dejar de auto-boxing lo haga por usted si está utilizando una versión bastante reciente de Java.

14

TL; DR

utilizar uno de estos para la conversión universal debe

//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 la forma de contestar a estas preguntas.

  • ¿Puede el BigDecimal tener una parte fraccionaria distinta de cero?
  • ¿Puede el BigDecimal no encajar en el rango Integer?
  • ¿Desea que las partes fraccionales distintas de cero se redondeen o trunquen?
  • ¿Cómo le gustaría que se redondearan partes fraccionales distintas de cero?

Si respondió no a las primeras 2 preguntas, podría simplemente usar BigDecimal.intValueExact() como otros han sugerido y dejarlo explotar cuando ocurra algo inesperado.

Si no está del todo seguro al 100% sobre la pregunta número 2, entonces intValue() es siempre la respuesta incorrecta.

Es muchísimo mejor

Vamos a usar las siguientes suposiciones basadas en las otras respuestas.

  • estamos bien con la pérdida de precisión y truncar el valor porque eso es lo intValueExact() y auto-boxeo hacer
  • queremos una excepción lanzada cuando el BigDecimal es mayor que el rango Integer porque cualquier otra cosa sería una locura a menos que tienen una necesidad muy específica de envoltura que sucede cuando sueltas los bits de orden superior.

Dados esos parámetros, intValueExact() arroja una excepción cuando no lo queremos si nuestra parte fraccionaria no es cero. Por otro lado, intValue() no arroja una excepción cuando debería si nuestro BigDecimal es demasiado grande.

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

Spock maravillosa prueba

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

he encontrado que lo anterior no funcionó para mí. Yo estaba tirando de un valor de celda de un JTable, pero no podía echar a duplicar o int etc. Mi solución:

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

donde la fila 0 siempre habría un número. Espero que esto ayude a cualquier persona que aún se desplaza!