Representación de valores monetarios en Java

Entiendo que BigDecimal es la mejor práctica recomendada para representar valores monetarios en Java. ¿Que usas? ¿Hay una mejor biblioteca que prefiera usar en su lugar?

BigDecimal todo el camino. He oído que algunas personas crean sus propias clases de Money 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 BigDecimal.ROUND_HALF_EVEN .

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-alpha para usar en un entorno de producción. Además, si cavas bajo el capó, verás que usan BigDecimal también .

Puede ser útil para las personas que llegan aquí por los motores de búsqueda para conocer JodaMoney: http://www.joda.org/joda-money/ .

No estoy expresando mi opinión aquí, pero hay argumentos bastante buenos contra BigDecimal que alguien probablemente debería tirar:

http://lemnik.wordpress.com/2011/03/25/bigdecimal-and-your-money/

Una biblioteca conveniente con la que me encontré antes es la biblioteca Joda-Money . Una de sus implementaciones está basada en BigDecimal. Se basa en la especificación ISO-4217 para monedas y puede admitir una lista de moneda personalizada (cargada a través de CVS).

Esta biblioteca tiene una pequeña cantidad de archivos que puede pasar 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, un gran decimal puede ser el camino a seguir.

De cualquier forma, probablemente extienda la clase para tener un .toString () que use el formato correcto, y como un lugar para poner otros métodos que puedan surgir (por un tiempo, multiplicar y dividir saldrá mal si el decimal no está 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 dinero.

Las representaciones y cálculos de coma flotante ( Double , Float ) son inexactos, lo que lleva a resultados erróneos.

Tienes que ser muy cuidadoso cuando se trata de tiempo y dinero.

Cuando trabajas con dinero, espero que todos sepan que nunca deben usar un flotador o un doble.

Pero no estoy seguro acerca de BigDecimal.

En la mayoría de los casos, estarás bien si simplemente haces un seguimiento de los centavos en un int o largo. De esta forma, nunca se ocupa de un lugar decimal.

Solo muestra dólares cuando lo imprime. Siempre trabaje con centavos internos usando enteros. Esto puede ser complicado si necesita dividir o necesita usar Math.abs ().

Sin embargo, podría importarte medio centavo o incluso una centésima de un centavo. No sé cuál es una buena manera de hacer esto. Es posible que deba ocuparse de la milésima de centavos y usar un largo. O tal vez te verás obligado a utilizar BigDecimal

Leería mucho más sobre esto, pero ignoraré a todos los que empiecen a hablar de usar un carro o un doble para representar el dinero. Solo están pidiendo problemas.

Siento que mi consejo no está completo, así que por favor, denle más. ¡Estás lidiando con tipos peligrosos!

Crear una clase Money es el camino a seguir. Usando BigDecimal (o incluso un int) debajo. Luego, use la clase Divisa para definir la convención de redondeo.

Desafortunadamente, sin la sobrecarga del operador, Java lo hace bastante desagradable creando tales tipos básicos.

Hay una mejor biblioteca, tiempo y dinero . IMO, es muy superior a las bibliotecas proporcionadas por el JDK por representar estos 2 conceptos.

Definitivamente no es BigDecimal. Hay tantas reglas especiales para redondeo y presentación que debe preocuparse.

Martin Fowler recomienda la implementación de una clase Money dedicada para representar las cantidades de moneda, y que también implementa reglas para la conversión de divisas.

Hola, 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 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 realice una cantidad extrema de pruebas unitarias y especialmente si trabaja con monedas diferentes. 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 la siguiente manera:

  assertEquals(Money.create("100.0 USD").add("10 GBP"),Money.create("116 USD")); 

Siempre hay restricciones y detalles involucrados. Cualquier persona sin suficiente experiencia para apreciar los sutiles problemas descritos en el siguiente artículo debería reconsiderar seriamente antes de lidiar con datos financieros del mundo real:

http://lemnik.wordpress.com/2011/03/25/bigdecimal-and-your-money

BigDecimal es apenas la única representación correcta o la única pieza del rompecabezas. Dadas ciertas condiciones, usar una clase Money respaldada por centavos almacenados como un entero podría ser suficiente y sería mucho más rápido que BigDecimal. Sí, eso implica el uso de dólares como montos de moneda y límites, pero tales restricciones son perfectamente aceptables para muchos casos de uso y todas las monedas tienen casos especiales para redondeo y subcategorías de todos modos, por lo que no existe una solución “universal”.