2008-11-12 25 views
85

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?Representación de valores monetarios en Java

+3

echa un vistazo a [JSR 354] (http://jcp.org/en/jsr/detail?id=354) – yegor256

+1

Aquí hay una clase de moneda que puede copiar y ampliar: http: // java-articles. info/articles /? p = 254 –

+0

Ver también la implementación de referencia de JSR-354 https: // github.com/JavaMoney/jsr354-ri – beat

Respuesta

74

BigDecimal todo el camino. He oído que algunas personas 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 un redondeo de BigDecimal.ROUND_HALF_EVEN.

Editar: Como se menciona en Don his answer, hay proyectos de código abierto como timeandmoney, y mientras que los aplaudo por tratar de evitar que los desarrolladores tener que reinventar la rueda, simplemente no tienen suficiente confianza en un pre -alpha library para usarlo en un entorno de producción. Además, si cavas bajo el capó, verás they use BigDecimal too.

+4

+1. Hemos decidido agregar una clase de contenedor que también consume una moneda. Esto es útil cuando se representan valores monetarios en tablas. – dhiller

+1

Sí, ese es un enfoque bastante común y tiene mucho sentido. Una advertencia para esto es cuando tienes que lidiar con el yen japonés, ya que no tienen una denominación monetaria menor como centavos, por lo que necesita sus propias reglas de redondeo. – ninesided

+3

@ninesided da un gran ejemplo de por qué rodar el suyo es una mala respuesta. "Ah, y por cierto, no funciona para $ CURRENCY_X". Esa es una buena señal de que tampoco funciona en muchas otras monedas. –

3

BigDecimal u otra representación de punto fijo es lo que generalmente se necesita para dinero.

Punto flotante (Double, Float) representaciones y cálculos inexactos, que conducen a resultados erróneos.

+7

Estrictamente hablando, BigDecimal también es inexacto; simplemente se corresponde mejor con el redondeo decimal que estamos acostumbrados en la vida diaria, y le permite especificar los modos de redondeo. –

+0

@Michael Borgwardt BigDecimal difiere de IEEE FP en que se especifica una escala explícita. Si bien no todas las operaciones son exactas, esto asegura que un conjunto de operaciones y comportamiento es * siempre * exacto y la escala es * constante * mientras que la escala para IEEE FP disminuye con el valor. –

+1

¿Qué tiene que ver eso con el dinero? Las organizaciones de contabilidad de todo el mundo generalmente tienen requisitos muy específicos sobre cómo hacer las matemáticas en su moneda. ¿BigDecimal se ajusta con precisión a todos y cada uno de estos estándares? ¿Lo hará el próximo año, cuando cambien esos estándares? Y BigDecimal ni siquiera se acerca a especificar reglas de redondeo útiles para monedas. –

7

Si solo está usando 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 manera, 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 (Durante mucho tiempo, multiplicar y dividir saldrá mal si el decimal no está ajustado)

Además, si usa definir su propia clase e interfaz, entonces puede reemplazar la implementación a voluntad.

+2

Tenga cuidado, incluso podría ser demasiado corto para mantener la deuda federal de los EE. UU. En centavos ... si no ahora en unos años. – Ingo

+3

Acepto: si hay un gran número de dólares (o tal vez si está realizando un seguimiento del dinero en yenes), debería usar BigDecimal, pero incluso entonces consideraría seriamente usar una clase de contenedor para él. Creo que la mayoría de la complejidad de programación proviene de personas que no definen clases pequeñas y simples en torno a colecciones y tipos intrínsecos. –

2

Tienes que tener mucho cuidado cuando se trata de tiempo y dinero.

Cuando está trabajando 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 de manera int o larga. De esta forma, nunca se ocupa de un lugar decimal.

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

Sin embargo, puede que te importe 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 se verá obligado a utilizar BigDecimal

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

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

+2

¿Por qué necesitaría ser "forzado" a utilizar BigDecimal? ¿De qué no estás seguro? Es claramente superior al trabajo con centavos, ya que le permite especificar explícitamente modos de redondeo. –

+1

@MichaelBorgwardt: sí, le permite especificar un pequeño subconjunto de los modos de redondeo que necesita para las monedas. ¿Asi que? (Sugerencia: el redondeo de monedas se decide, generalmente, por las organizaciones contables nacionales. Están perfectamente felices de lanzar casos especiales extraños. Consulte http://stackoverflow.com/questions/5134237/swiss-and-argentinian-currency-fourth- redondeo de dígitos decimales por solo una de las muchas razones entretenidas por las que el redondeo de BigDecimal es completamente inútil aquí.) –

+0

@James: ¿Cómo es exactamente "inútil"? ¿Cómo sería más difícil implementar estos casos especiales con BigDecimal que con algo más? –

2

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 hace que crear estos tipos básicos sea bastante desagradable.

2

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

+3

Esta respuesta se publicó hace tres años. Hoy, el proyecto timeandmoney sigue siendo pre-alfa según ese enlace. –

+1

@JamesMoore Buena llamada.La respuesta ahora es 7 años y el proyecto aún no es estable. – Navin

1

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

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

+6

y el tipo de datos subyacente de su clase Money? BigDecimal. – ninesided

+1

Eso no es verdad. Podría usar Integer en la clase de dinero, que es lo que hace Martin. He hecho esto muchas veces. – egervari

+0

La recomendación es correcta; Los cálculos que involucran dinero son un gran cúmulo de casos especiales que cambian con el tiempo. BigDecimal puede ser útil como una pequeña parte de la solución, pero ciertamente no es general. –

0

Puede usar la clase DecimalFormat cuando finalmente muestra un valor de moneda. Proporciona soporte de localización y es bastante extensible.

0

Encapsularía BigDecimal en la clase Money que también tiene una moneda como la mencionada 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 se agrega un constructor conveniente que toma una cadena o un método de fábrica que hace la misma manera que usted puede escribir su pruebas de algo como esto:

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

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

+0

Gracias. He querido agregar una nota de seguimiento sobre Joda Money. ¿Lo has usado? – dshaw

+2

+1 parece interesante, me alegro de ver que es 'BigDecimal' bajo el capó! – ninesided

1

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. BigDecimal Tutorial.

8

Una biblioteca conveniente que 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 uno puede pasar rápidamente si se necesitan modificaciones. Joda-Money se publica bajo la licencia Apache 2.0.

0

siempre hay limitaciones y características específicas involucradas. Cualquier persona sin experiencia suficiente para apreciar las cuestiones sutiles descritos en el siguiente artículo debe reconsiderar seriamente antes de tratar con los 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 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".

+1

Esto parece ser un comentario en otra publicación en lugar de una respuesta real. También es demasiado mordaz. Por favor, intenta ser más civil en el futuro. –

+0

Punto razonable, editado. – Craig

Cuestiones relacionadas