Java Money og Currency API

1. Oversikt

JSR 354 - “Valuta og penger” adresserer standardiseringen av valutaer og pengebeløp i Java.

Målet er å legge til et fleksibelt og utvidbart API til Java-økosystemet og gjøre arbeidet med pengebeløp enklere og tryggere.

JSR tok seg ikke inn i JDK 9, men er en kandidat for fremtidige JDK-utgivelser.

2. Oppsett

La oss først definere avhengigheten til vår pom.xml fil:

 org.javamoney moneta 1.1 

Den siste versjonen av avhengigheten kan sjekkes her.

3. JSR-354 Funksjoner

Målene med API-en "valuta og penger":

  • Å tilby et API for håndtering og beregning av pengebeløp
  • Å definere klasser som representerer valutaer og pengebeløp, samt monetær avrunding
  • Å håndtere valutakurser
  • Å håndtere formatering og analyse av valutaer og pengebeløp

4. Modell

Hovedklassene i JSR-354 spesifikasjonen er avbildet i følgende diagram:

Modellen har to hovedgrensesnitt Valutaenhet og Monetært beløp, forklart i de følgende avsnittene.

5. Valutaenhet

Valutaenhet modellerer de minimale egenskapene til en valuta. Forekomster kan fås ved hjelp av Monetary.getCurrency metode:

@Test offentlig ugyldig givenCurrencyCode_whenString_thanExist () {CurrencyUnit usd = Monetary.getCurrency ("USD"); assertNotNull (usd); assertEquals (usd.getCurrencyCode (), "USD"); assertEquals (usd.getNumericCode (), 840); assertEquals (usd.getDefaultFractionDigits (), 2); }

Vi skaper Valutaenhet bruker en String representasjon av valutaen, kan dette føre til en situasjon der vi prøver å lage en valuta med ikke-eksisterende kode. Å lage valutaer med ikke-eksisterende koder øker en Ukjent Valuta unntak:

@Test (forventet = UnknownCurrencyException.class) offentlig ugyldig givenCurrencyCode_whenNoExist_thanThrowsError () {Monetary.getCurrency ("AAA"); } 

6. MonetaryAmount

MonetaryAmount er en numerisk fremstilling av et pengebeløp. Det er alltid forbundet med Valutaenhet og definerer en monetær representasjon av en valuta.

Beløpet kan implementeres på forskjellige måter, med fokus på oppførselen til et krav til monetær representasjon, definert av hver konkrete brukssak. For eksempel. Penger og FastPenger er implementeringer av Monetært beløp grensesnitt.

FastPenger redskaper MonetaryAmount ved hjelp av lang som numerisk representasjon, og er raskere enn BigDecimal på bekostning av presisjon; den kan brukes når vi trenger ytelse og presisjon er ikke et problem.

En generisk forekomst kan opprettes ved hjelp av en standard fabrikk. La oss vise den forskjellige måten å oppnå Monetært beløp forekomster:

@Test offentlig ugyldig givenAmounts_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. Pengearitmetikk

Vi kan utføre pengearitmetikk mellom Penger og FastPenger men vi må være forsiktige når vi kombinerer forekomster av disse to klassene.

For eksempel når vi sammenligner en Euro-forekomst av FastPenger med en Euro-forekomst av Penger resultatet er at de ikke er de samme:

@Test offentlig ugyldig gittCurrency_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"))); }

Vi kan utføre add, subtrahere, multiplisere, dele og andre monetære aritmetiske operasjoner ved hjelp av metodene som tilbys av MonetaryAmount klasse.

Aritmetiske operasjoner skal kaste en Aritmetisk unntak, hvis de aritmetiske operasjonene mellom beløpene overgår egenskapene til den numeriske representasjonstypen som brukes, for eksempel hvis vi prøver å dele en etter tre, får vi en Aritmetisk unntak fordi resultatet er et uendelig tall:

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

Når du legger til eller trekker fra beløp, er det bedre å bruke parametere som er forekomster av MonetaryAmount, ettersom vi må sørge for at begge beløp har samme valuta for å utføre operasjoner mellom beløp.

7.1. Beregning av beløp

Totalt kan beløp beregnes på flere måter, en måte er ganske enkelt å kjede beløpene med:

@Test offentlig ugyldig givenAmounts_whenSummed_thanCorrect () {MonetaryAmount [] monetaryAmounts = new MonetaryAmount [] {Money.of (100, "CHF"), Money.of (10.20, "CHF"), Money.of (1.15, "CHF") }; Money sumAmtCHF = Money.of (0, "CHF"); for (MonetaryAmount monetaryAmount: monetaryAmounts) {sumAmtCHF = sumAmtCHF.add (monetaryAmount); } assertEquals ("CHF 111,35", sumAmtCHF.toString ()); }

Kjetting kan også brukes til å trekke fra:

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

Multiplisere:

MonetaryAmount multiplyAmount = oneDolar.multiply (0,25);

Eller dele:

MonetaryAmount divideAmount = oneDolar.divide (0,25);

La oss sammenligne de aritmetiske resultatene våre ved hjelp av Strings, gitt det med Strings fordi resultatet også inneholder valutaen:

@Test offentlig ugyldighet givenArithmetic_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"). Subtraherer (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", trukketAmount.toString ()); assertEquals ("USD 0,25", multiplyAmount.toString ()); assertEquals ("USD 4", divideAmount.toString ()); }

8. Pengeavrunding

Monetær avrunding er ingenting annet enn en konvertering fra et beløp med ubestemt presisjon til et avrundet beløp.

Vi bruker getDefaultRounding API levert av Monetære klasse for å gjøre konverteringen. Standard avrundingsverdier er gitt av valutaen:

@Test offentlig ugyldig givenAmount_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. Valutakonvertering

Valutakonvertering er et viktig aspekt ved å håndtere penger. Dessverre har disse konverteringene et stort utvalg av forskjellige implementeringer og brukssaker.

API-et fokuserer på de vanlige aspektene ved valutakonvertering basert på kilde, målvaluta og valutakurs.

Valutakonvertering eller tilgang til valutakurser kan parametriseres:

@Test offentlig ugyldig givenAmount_whenConversion_thenNotNull () {MonetaryAmount oneDollar = Monetary.getDefaultAmountFactory (). SetCurrency ("USD") .setNumber (1) .create (); CurrencyConversion conversionEUR = MonetaryConversions.getConversion ("EUR"); MonetaryAmount convertAmountUSDtoEUR = oneDollar.with (conversionEUR); assertEquals ("USD 1", oneDollar.toString ()); assertNotNull (convertAmountUSDtoEUR); }

En konvertering er alltid bundet til valuta. Monetært beløp kan bare konverteres ved å sende en Valutakonvertering til beløpet med metode.

10. Valutaformatering

Formateringen gir tilgang til formater basert på java.util.Locale. I motsetning til JDK er formatørene definert av dette API-et trådsikkert:

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

Her bruker vi det forhåndsdefinerte formatet og lager et tilpasset format for valutaene våre. Bruken av standardformatet er grei å bruke metodeformatet til Monetære formater klasse. Vi definerte vårt egendefinerte format og innstilte mønsteregenskapen til formatbyggeren.

Som før fordi valutaen er inkludert i resultatet, tester vi resultatene våre ved hjelp av Strenger:

@Test offentlig ugyldig givenAmount_whenCustomFormat_thanEquals () {MonetaryAmount oneDollar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat (AmountFormatQueryBuilder. Of (Locale.US) .set (CurrencyStyle.NAME) .set ("mønster", "00000,00 ¤"). Build ()); Streng customFormatted = customFormat.format (oneDollar); assertNotNull (customFormat); assertEquals ("USD 1", oneDollar.toString ()); assertEquals ("00001,00 amerikanske dollar", tilpasset formatert); }

11. Oppsummering

I denne raske artikkelen har vi dekket det grunnleggende om Java Money & Currency JSR.

Monetære verdier brukes overalt, og Java tilbyr begynner å støtte og håndtere pengeverdier, aritmetikk eller valutakonvertering.

Som alltid kan du finne koden fra artikkelen på Github.


$config[zx-auto] not found$config[zx-overlay] not found