Entiendo que BigDecimal es la mejor práctica recomendada para representar valores monetarios en Java. ¿Que usas? ¿Hay alguna biblioteca mejor que prefieras usar en su lugar?
Entiendo que BigDecimal es la mejor práctica recomendada para representar valores monetarios en Java. ¿Que usas? ¿Hay alguna biblioteca mejor que prefieras usar en su lugar?
Respuestas:
BigDecimal
todo el camino. He oído hablar de algunas personas que crean sus propias clases Cash
o Money
que encapsulan un valor en efectivo con la moneda, pero bajo la piel sigue siendo un BigDecimal
, probablemente con BigDecimal.ROUND_HALF_EVEN
redondeo.
Editar: como Don menciona en su respuesta , hay proyectos de código abierto como timeandmoney , y aunque los aplaudo por tratar de evitar que los desarrolladores tengan que reinventar la rueda, simplemente no tengo suficiente confianza en una biblioteca pre-alfa para usar en un entorno de producción. Además, si excavas debajo del capó, verás que BigDecimal
también lo usan .
Puede ser útil para las personas que llegan aquí mediante motores de búsqueda conocer JodaMoney: http://www.joda.org/joda-money/ .
BigDecimal
debajo del capó!
No estoy expresando mi opinión aquí, pero hay argumentos bastante buenos contra BigDecimal que alguien probablemente debería descartar:
http://lemnik.wordpress.com/2011/03/25/bigdecimal-and-your-money/
Una biblioteca conveniente con la que me encontré anteriormente es la biblioteca Joda-Money . Una de sus implementaciones se basa de hecho en BigDecimal. Se basa en la ISO-4217 especificación para monedas y puede admitir una lista de monedas personalizada (cargada a través de CVS).
Esta biblioteca tiene una pequeña cantidad de archivos que se pueden revisar rápidamente si se necesitan modificaciones. Joda-Money se publica bajo la licencia Apache 2.0.
Si solo usa dólares y centavos, usaría un largo (compensado por 2 lugares decimales). Si necesita más detalles, el decimal grande puede ser el camino a seguir.
De cualquier manera, probablemente ampliaría la clase para tener un .toString () que use el formato correcto, y como un lugar para colocar otros métodos que puedan surgir (durante mucho tiempo, multiplicar y dividir saldrá mal si el decimal no es 't ajustado)
Además, si usa definir su propia clase e interfaz, puede reemplazar la implementación a voluntad.
BigDecimal
u otra representación de punto fijo es lo que generalmente se necesita para el dinero.
Las representaciones y cálculos de coma flotante ( Double
, Float
) son inexactos, lo que da lugar a resultados erróneos.
Hay que tener mucho cuidado al tratar con el tiempo y el dinero.
Cuando trabaje con dinero, espero que todos sepan que nunca deben usar un flotador o un doble.
Pero no estoy seguro de BigDecimal.
En la mayoría de los casos, estará bien si solo realiza un seguimiento de los centavos en un int o long. De esta forma, nunca se ocupará de un decimal.
Solo muestra dólares cuando lo imprime. Siempre trabaje con centavos internos usando números enteros. Esto puede ser complicado si necesita dividir o utilizar Math.abs ().
Sin embargo, es posible que le importe medio centavo, o incluso una centésima de centavo. No sé cuál es una buena forma de hacer esto. Es posible que solo tenga que lidiar con una milésima de centavos y usar un largo. O tal vez te verás obligado a usar BigDecimal
Leería mucho más sobre esto, pero ignoraría a todos los que comienzan a hablar de usar un flotador o un doble para representar dinero. Solo están buscando problemas.
Siento que mi consejo no está completo, así que por favor, reflexione más sobre él. ¡Estás tratando con tipos peligrosos!
Crear una clase de Money es el camino a seguir. Usando BigDecimal (o incluso un int) debajo. Luego, use la clase de moneda para definir la convención de redondeo.
Desafortunadamente, sin el operador sobrecargado, Java hace que sea bastante desagradable crear tipos tan básicos.
Hay una biblioteca mejor, tiempo y dinero . En mi opinión, es muy superior a las bibliotecas proporcionadas por el JDK para representar estos 2 conceptos.
Definitivamente no BigDecimal. Hay tantas reglas especiales para el redondeo y la presentación de las que debe preocuparse.
Martin Fowler recomienda la implementación de una clase Money dedicada para representar los montos de moneda, y que también implementa reglas para la conversión de moneda.
Oye, aquí hay un artículo muy interesante sobre BigDecimal y un ejemplo ilustrativo de por qué a veces se usa en lugar de dobles. Tutorial de BigDecimal .
Puede usar la clase DecimalFormat cuando finalmente muestre un valor de moneda. Proporciona soporte de localización y es bastante extensible.
Encapsularía BigDecimal en la clase Money que también tiene una moneda como alguien mencionado anteriormente. Lo importante es que hagas una cantidad extrema de pruebas unitarias y especialmente si trabajas con diferentes monedas. También es una buena idea si agrega un constructor conveniente que tome una cadena o un método de fábrica que haga lo mismo para que pueda escribir sus pruebas de esta manera:
assertEquals(Money.create("100.0 USD").add("10 GBP"),Money.create("116 USD"));
Siempre hay limitaciones y detalles involucrados. Cualquiera que no tenga suficiente experiencia para apreciar los problemas sutiles descritos en el siguiente artículo debe reconsiderar seriamente antes de tratar con datos financieros del mundo real:
http://lemnik.wordpress.com/2011/03/25/bigdecimal-and-your-money
BigDecimal no es la única representación correcta o la única pieza del rompecabezas. Dadas ciertas condiciones, usar una clase Money respaldada por centavos almacenados como un número entero podría ser suficiente y sería mucho más rápido que BigDecimal. Sí, eso implica el uso de dólares como moneda y límites de montos, pero tales restricciones son perfectamente aceptables para muchos casos de uso y todas las monedas tienen casos especiales de redondeo y sub-denominaciones de todos modos, por lo que no existe una solución "universal".