Cómo trabajar con importes, ratios y divisas en Java

Publicado por pico.dev el , actualizado el .
blog-stack java planeta-codigo programacion
Comentarios

Aún en Java 8 no tenemos una API incluida en el JDK dedicada al manejo de importes, divisas y conversiones. Si la especificación JSR-354 se incluye en alguna versión podremos hacer uso de ella sin necesidad de ninguna dependencia adicional, pero si tenemos necesidad ahora podemos usar la librería que ha producido la especificación. Usando las clases y métodos de la API evitaremos hacer y mantener una implementación nosotros mismos que además seguro no llega al nivel de esta.

Java

Las aplicaciones de comercio electrónico o que realizan operaciones financieras con importes seguro que necesitan una forma de representar un importe junto con una divisa. También si necesitan convertir importes en diferentes divisas necesitarán obtener los ratios de conversión de alguna fuente, en el artículo Servicio para obtener ratios de conversión entre divisas comentaba uno que podemos usar, Open Exchange Rates. Java incluye clases para datos numéricos y con ellos se pueden representar importes como por ejemplo BigDecimal. Para importes no debemos usar en ningún caso un tipo de dato float o double ya que estos son incapaces de representar ciertos valores de forma exacta, usando float y double tendremos errores de precisión, redondeo y representación. En vez de crear un nuevo tipo de datos (una clase) que tenga como propiedades un BigDecimal para el importe y un String o similar para representar la divisa además de implementar las varias operaciones aritméticas y de comparación entre otras muchas cosas que necesitaremos podemos usar la librería que la especificación JSR-354 proporciona una API dedicada a importes y divisas en Java. En Java 8 no se incluyó pero en una futura versión quizá si se incluya en el propio JDK. En este artículo comentaré como usando Java 8 podemos hacer uso de esta API desde ya y que ofrece.

Aunque la especificación no es parte de Java aún el grupo de trabajo encargado ha generado una dependencia que podemos usar. En el repositorio de GitHub podemos encontrar el código de la librería. Incluyéndola como dependencia de un proyecto podemos usarla, usando Gradle con:

La librería hace uso de lambdas, una de las novedades que introdujo de Java 8 en el lenguaje, y nos facilita varias funcionalidades. También permite usar streams. Veamos algunas de las posibilidades.

Representación de divisas e importes

Las divisas se representan con CurrencyUnit y los importes se representan usando la clase MoneyAmount, tenemos varias formas de crear instancias de estas clases.

La API ofrece varios métodos para extraer los valores numéricos, la parte entera y decimal, que una instancia de MoneyAmount contiene así como obtener los valores en un tipo de datos más básico como BigDecimal.

Operaciones aritméticas, de comparación y operaciones personalizadas

Podemos hacer operaciones aritméticas (suma, resta, multiplicación y división) entre dos importes.

También podremos hacer comparaciones:

Redondear importes

E incluso implementar operaciones más complejas y habituales personalizadas con la clase MonetaryOperator que se puede aplicar usando el método with de MonerayAmount.

Formateado y analizado

Dependiendo de país o la moneda los importes se representan de forma diferente, por ejemplo, en Estados Unidos se usa «,» como separador de millares y «.» como separador de los decimales, en España es diferente, se usa «.» para los millares y «,» para los decimales. También hay monedas que no tienen decimales como el Yen japonés. Disponemos de métodos y clases para formatear correctamente el importe.

Podemos hacer la operación contraria parseando o analizando la cadena, obtener un objeto MoneyAmount desde su representación en String.

Ratios de conversión, conversiones entre divisas

Si necesitamos convertir el importe de una moneda a otra necesitaremos el ratio de conversión entre las monedas, es decir, por cada dólar estadounidense cuántos euros son si queremos hacer una conversión de USD a euro. Se puede obtener el ratio de conversión o hacer la conversión directamente entre las dos monedas. En el siguiente código se muestra cuántos euros son 10 USD con la cotización entre las divisas en el momento de escribir el artículo.

La librería incluye varias fuentes para las cotizaciones de cada moneda, una de ellas es el Banco Central Europeo pero también podemos crear la implementación de una nueva fuente que por ejemplo use Open Exchange Rates.

Streams y filtros

Por si todo esto fuera poco podemos usar las características de programación funcional de Java 8 ya que la librería ofrece soporte para streams para ejemplo filtrar o para agrupar.

El código fuente completo del ejemplo está en uno de mis repositorios de GitHub.