Java Money en de Currency API

1. Overzicht

JSR 354 - "Valuta en geld" behandelt de standaardisatie van valuta's en geldbedragen in Java.

Het doel is om een ​​flexibele en uitbreidbare API toe te voegen aan het Java-ecosysteem en het werken met geldbedragen eenvoudiger en veiliger te maken.

De JSR heeft zijn weg naar JDK 9 niet gevonden, maar is een kandidaat voor toekomstige JDK-releases.

2. Installatie

Laten we eerst de afhankelijkheid van ons definiëren pom.xml het dossier:

 org.javamoney moneta 1.1 

De laatste versie van de afhankelijkheid kan hier worden gecontroleerd.

3. JSR-354 kenmerken

De doelen van de API 'Valuta en geld':

  • Om een ​​API te bieden voor het verwerken en berekenen van geldbedragen
  • Om klassen te definiëren die valuta's en geldbedragen vertegenwoordigen, evenals geldafrondingen
  • Omgaan met wisselkoersen
  • Om te gaan met het opmaken en ontleden van valuta's en geldbedragen

4. Model

De hoofdklassen van de JSR-354-specificatie worden weergegeven in het volgende diagram:

Het model heeft twee hoofdinterfaces Munteenheid en Monetair bedrag, uitgelegd in de volgende secties.

5. Munteenheid

Munteenheid modelleert de minimale eigenschappen van een valuta. De exemplaren kunnen worden verkregen met behulp van de Monetary.getCurrency methode:

@Test openbare ongeldige gegevenCurrencyCode_whenString_thanExist () {CurrencyUnit usd = Monetary.getCurrency ("USD"); assertNotNull (usd); assertEquals (usd.getCurrencyCode (), "USD"); assertEquals (usd.getNumericCode (), 840); assertEquals (usd.getDefaultFractionDigits (), 2); }

We creëren Munteenheid gebruik maken van een Draad weergave van de valuta, kan dit leiden tot een situatie waarin we proberen een valuta te creëren met een niet-bestaande code. Het creëren van valuta's met niet-bestaande codes levert een op Onbekende valuta uitzondering:

@Test (verwacht = UnknownCurrencyException.class) openbare ongeldige gegevenCurrencyCode_whenNoExist_thanThrowsError () {Monetary.getCurrency ("AAA"); } 

6. Monetair bedrag

Monetair bedrag is een numerieke weergave van een geldbedrag. Het wordt altijd geassocieerd met Munteenheid en definieert een monetaire weergave van een valuta.

Het bedrag kan op verschillende manieren worden geïmplementeerd, waarbij de nadruk ligt op het gedrag van monetaire representatievereisten, gedefinieerd door elk concreet gebruik. Bijvoorbeeld. Geld en Snel geld zijn implementaties van de Monetair bedrag koppel.

Snel geld werktuigen Monetair bedrag gebruik makend van lang als numerieke weergave, en is sneller dan BigDecimal ten koste van precisie; het kan worden gebruikt wanneer we prestaties nodig hebben en precisie geen probleem is.

Een generiek exemplaar kan worden gemaakt met behulp van een standaardfabriek. Laten we de andere manier van verkrijgen laten zien Monetair bedrag gevallen:

@Test openbare ongeldige gegevenAmounts_whenStringified_thanEquals () {CurrencyUnit usd = Monetary.getCurrency ("USD"); MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory () .setCurrency (usd) .setNumber (200) .create (); Money moneyof = Money.of (12, usd); FastMoney fastmoneyof = FastMoney.of (2, usd); assertEquals ("USD", usd.toString ()); assertEquals ("USD 200", fstAmtUSD.toString ()); assertEquals ("USD 12", moneyof.toString ()); assertEquals ("USD 2.00000", fastmoneyof.toString ()); }

7. Monetaire rekenkunde

We kunnen monetaire berekeningen uitvoeren tussen Geld en Snel geld maar we moeten voorzichtig zijn wanneer we instanties van deze twee klassen combineren.

Als we bijvoorbeeld één Euro-instantie van Snel geld met één Euro-instantie van Geld het resultaat is dat ze niet hetzelfde zijn:

@Test openbare ongeldigheid gegevenCurrencies_whenCompared_thanNotequal () {MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); Money oneEuro = Money.of (1, "EUR"); assertFalse (oneEuro.equals (FastMoney.of (1, "EUR")))); assertTrue (oneDolar.equals (Money.of (1, "USD"))); }

We kunnen optellen, aftrekken, vermenigvuldigen, delen en andere monetaire rekenkundige bewerkingen uitvoeren met behulp van de methoden die worden geboden door de Monetair bedrag klasse.

Rekenkundige bewerkingen zouden een ArithmeticException, als de rekenkundige bewerkingen tussen bedragen beter presteren dan de mogelijkheden van het gebruikte numerieke weergavetype, bijvoorbeeld als we proberen een door drie te delen, krijgen we een ArithmeticException omdat het resultaat een oneindig aantal is:

@Test (verwacht = ArithmeticException.class) public void givenAmount_whenDivided_thanThrowsException () {MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); oneDolar.divide (3); }

Bij het optellen of aftrekken van bedragen is het beter om parameters te gebruiken die voorbeelden zijn van Monetair bedrag, aangezien we ervoor moeten zorgen dat beide bedragen dezelfde valuta hebben om bewerkingen tussen bedragen uit te voeren.

7.1. Bedragen berekenen

Een totaal van bedragen kan op meerdere manieren worden berekend, een manier is simpelweg om de bedragen te koppelen aan:

@Test openbare leegte gegevenAmounts_whenSummed_thanCorrect () {MonetaryAmount [] monetaryAmounts = nieuw MonetaryAmount [] {Money.of (100; "CHF"), Money.of (10,20; "CHF"), Money.of (1,15; "CHF") }; Money sumAmtCHF = Money.of (0; "CHF"); voor (MonetaryAmount monetaryAmount: monetaryAmounts) {sumAmtCHF = sumAmtCHF.add (monetaryAmount); } assertEquals ("CHF 111.35", sumAmtCHF.toString ()); }

Chaining kan ook worden toegepast op aftrekken:

Money calcAmtUSD = Money.of (1, "USD"). Aftrekken (fstAmtUSD); 

Vermenigvuldigen:

MonetaryAmount multiplyAmount = oneDolar.multiply (0.25);

Of verdelen:

MonetaryAmount divideAmount = oneDolar.divide (0.25);

Laten we onze rekenkundige resultaten vergelijken met Strings, aangezien het resultaat ook de valuta bevat:

@Test openbare ongeldigheid gegevenArithmetic_whenStringified_thanEqualsAmount () {CurrencyUnit usd = Monetary.getCurrency ("USD"); Money moneyof = Money.of (12, usd); MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory () .setCurrency (usd) .setNumber (200.50) .create (); MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); Money subtractedAmount = Money.of (1, "USD"). Aftrekken (fstAmtUSD); MonetaryAmount multiplyAmount = oneDolar.multiply (0.25); MonetaryAmount divideAmount = oneDolar.divide (0.25); assertEquals ("USD", usd.toString ()); assertEquals ("USD 1", oneDolar.toString ()); assertEquals ("USD 200.5", fstAmtUSD.toString ()); assertEquals ("USD 12", moneyof.toString ()); assertEquals ("USD -199.5", subtractedAmount.toString ()); assertEquals ("USD 0,25", multiplyAmount.toString ()); assertEquals ("USD 4", divideAmount.toString ()); }

8. Monetaire afronding

Monetaire afronding is niets anders dan een omrekening van een bedrag met een onbepaalde precisie naar een afgerond bedrag.

We gebruiken de getDefaultRounding API geleverd door de Monetair klasse om de conversie te maken. De standaardafrondingswaarden worden geleverd door de valuta:

@Test openbare leegte gegevenAmount_whenRounded_thanEquals () {MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory () .setCurrency ("EUR"). SetNumber (1.30473908) .create (); MonetaryAmount roundEUR = fstAmtEUR.with (Monetary.getDefaultRounding ()); assertEquals ("EUR 1.30473908", fstAmtEUR.toString ()); assertEquals ("EUR 1.3", roundEUR.toString ()); }

9. Valutaconversie

Valutaconversie is een belangrijk aspect van het omgaan met geld. Helaas hebben deze conversies een grote verscheidenheid aan verschillende implementaties en use-cases.

De API richt zich op de algemene aspecten van valutaconversie op basis van de bron, doelvaluta en wisselkoers.

Valutaconversie of toegang tot wisselkoersen kan worden geparametriseerd:

@Test openbare leegte gegevenAmount_whenConversion_thenNotNull () {MonetaryAmount oneDollar = Monetary.getDefaultAmountFactory (). SetCurrency ("USD") .setNumber (1) .create (); CurrencyConversion conversionEUR = MonetaryConversions.getConversion ("EUR"); MonetaryAmount geconverteerdAmountUSDtoEUR = oneDollar.with (conversionEUR); assertEquals ("USD 1", oneDollar.toString ()); assertNotNull (geconverteerdeAmountUSDtoEUR); }

Een omrekening is altijd valuta-gebonden. Monetair bedrag kan eenvoudig worden omgezet door een Wisselkoers aan de bedragen met methode.

10. Valuta-opmaak

De opmaak geeft toegang tot indelingen op basis van java.util.Locale. In tegenstelling tot de JDK zijn de formatters die door deze API worden gedefinieerd, thread-safe:

@Test openbare leegte gegevenLocale_whenFormatted_thanEquals () {MonetaryAmount oneDollar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); MonetaryAmountFormat formatUSD = MonetaryFormats.getAmountFormat (Locale.US); String usFormatted = formatUSD.format (oneDollar); assertEquals ("USD 1", oneDollar.toString ()); assertNotNull (formatUSD); assertEquals ("USD1.00", usFormatted); }

Hier gebruiken we het vooraf gedefinieerde formaat en maken we een aangepast formaat voor onze valuta's. Het gebruik van het standaardformaat is eenvoudig met behulp van het methodeformaat van het Monetaire formaten klasse. We hebben onze aangepaste indeling gedefinieerd door de patroondeigenschap van de format-querybuilder in te stellen.

Zoals eerder, omdat de valuta is opgenomen in het resultaat, testen we onze resultaten met Snaren:

@Test openbare ongeldige gegevenAmount_whenCustomFormat_thanEquals () {MonetaryAmount oneDollar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat (AmountFormatQueryBuilder. Van (Locale.US) .set (CurrencyStyle.NAME) .set ("patroon", "00000.00 ¤"). Build ()); String customFormatted = customFormat.format (oneDollar); assertNotNull (customFormat); assertEquals ("USD 1", oneDollar.toString ()); assertEquals ("00001.00 US Dollar", customFormatted); }

11. Samenvatting

In dit korte artikel hebben we de basisprincipes van de Java Money & Currency JSR behandeld.

Monetaire waarden worden overal gebruikt, en Java begint met het ondersteunen en verwerken van geldwaarden, rekenkundige bewerkingen of valutaconversie.

Zoals altijd kun je de code uit het artikel op Github vinden.