Java Money i Currency API

1. Pregled

JSR 354 - "Valuta i novac" govori o standardizaciji valuta i novčanih iznosa na Javi.

Cilj mu je dodati fleksibilni i proširivi API ekosustavu Java i učiniti rad s novčanim iznosima jednostavnijim i sigurnijim.

JSR se nije probio u JDK 9, ali je kandidat za buduća izdanja JDK.

2. Postavljanje

Prvo, definirajmo ovisnost u našoj pom.xml datoteka:

 org.javamoney moneta 1.1 

Najnoviju verziju ovisnosti možete provjeriti ovdje.

3. Značajke JSR-354

Ciljevi API-ja „Valuta i novac“:

  • Osigurati API za rukovanje i izračunavanje novčanih iznosa
  • Definirati klase koje predstavljaju valute i novčane iznose, kao i monetarno zaokruživanje
  • Za rješavanje tečaja valuta
  • Baviti se formatiranjem i raščlanjivanjem valuta i novčanih iznosa

4. Model

Glavne klase specifikacije JSR-354 prikazane su na sljedećem dijagramu:

Model ima dva glavna sučelja CurrencyUnit i MonetaryAmount, objašnjeno u sljedećim odjeljcima.

5. CurrencyUnit

CurrencyUnit modelira minimalna svojstva valute. Njegovi se primjeri mogu dobiti pomoću Monetary.getCurrency metoda:

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

Mi stvaramo CurrencyUnit pomoću a Niz predstavljanja valute, to bi moglo dovesti do situacije u kojoj pokušavamo stvoriti valutu s nepostojećim kodom. Stvaranje valuta s nepostojećim kodovima povisuje Nepoznata valuta iznimka:

@Test (očekuje se = UnknownCurrencyException.class) javna praznina givenCurrencyCode_whenNoExist_thanThrowsError () {Monetary.getCurrency ("AAA"); } 

6. MonetaryAmount

MonetaryAmount je numerički prikaz novčanog iznosa. Uvijek je povezano s CurrencyUnit i definira novčani prikaz valute.

Iznos se može provesti na različite načine, usredotočujući se na ponašanje zahtjeva novčanog predstavljanja, definiranih u svakom konkretnom slučaju upotrebe. Na primjer. Novac i FastMoney su implementacije MonetaryAmount sučelje.

FastMoney provodi MonetaryAmount koristeći dugo kao numerički prikaz i brži je od BigDecimal po cijenu preciznosti; može se koristiti kada su nam potrebne performanse, a preciznost nije problem.

Generička instanca može se stvoriti pomoću zadane tvornice. Pokažimo drugačiji način dobivanja MonetaryAmount primjerci:

@Test javna praznina givenAmounts_whenStringified_thanEquals () {CurrencyUnit usd = Monetary.getCurrency ("USD"); MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory () .setCurrency (usd) .setNumber (200) .create (); Novac novac od = Money.of (12, usd); FastMoney fastmoneyof = FastMoney.of (2, usd); assertEquals ("USD", usd.toString ()); assertEquals ("200 USD", fstAmtUSD.toString ()); assertEquals ("12 USD", moneyof.toString ()); assertEquals ("2,00 000 USD", fastmoneyof.toString ()); }

7. Monetarna aritmetika

Možemo izvršiti novčanu aritmetiku između Novac i FastMoney ali moramo biti oprezni kada kombiniramo primjerke ove dvije klase.

Na primjer, kada usporedimo jedan euro primjerak FastMoney s jednim primjerom eura Novac rezultat je da nisu isti:

@Test javna praznina givenCurrencies_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"))); }

Možemo izvoditi zbrajanje, oduzimanje, množenje, dijeljenje i druge novčane aritmetičke operacije koristeći metode predviđene u MonetaryAmount razred.

Aritmetičke operacije trebaju baciti znak ArithmeticException, ako aritmetičke operacije između iznosa nadmašuju mogućnosti vrste numeričkog prikaza, na primjer, ako pokušavamo podijeliti jedan s tri, dobit ćemo ArithmeticException jer je rezultat beskonačan broj:

@Test (očekuje se = ArithmeticException.class) javna praznina givenAmount_whenDivided_thanThrowsException () {MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); oneDolar.divide (3); }

Prilikom dodavanja ili oduzimanja iznosa bolje je koristiti parametre koji su primjeri MonetaryAmount, jer moramo osigurati da oba iznosa imaju istu valutu za obavljanje operacija između iznosa.

7.1. Izračunavanje iznosa

Ukupno se iznosi mogu izračunati na više načina, jedan od načina je jednostavno povezivanje iznosa sa:

@Test javna praznina givenAmounts_whenSummed_thanCorrect () {MonetaryAmount [] monetarni iznosi = novi monetarni iznos [] {Money.of (100, "CHF"), Money.of (10.20, "CHF"), Money.of (1.15, "CHF") }; Novčana sumaAmtCHF = Money.of (0, "CHF"); for (MonetaryAmount monetarni iznos: monetarni iznosi) {sumAmtCHF = sumAmtCHF.add (monetarni iznos); } assertEquals ("CHF 111,35", sumAmtCHF.toString ()); }

Lanciranje se također može primijeniti na oduzimanje:

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

Množenje:

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

Ili dijeljenje:

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

Usporedimo naše aritmetičke rezultate pomoću značajke Strings, s obzirom na to da imaju značajku Strings, jer rezultat također sadrži valutu:

@Test javna praznina givenArithmetic_whenStringified_thanEqualsAmount () {CurrencyUnit usd = Monetary.getCurrency ("USD"); Novac novac od = Money.of (12, usd); MonetaryAmount fstAmtUSD = Monetary.getDefaultAmountFactory () .setCurrency (usd) .setNumber (200.50) .create (); MonetaryAmount oneDolar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); Novac oduzeti iznos = Novac.od (1, "USD"). Oduzeti (fstAmtUSD); MonetaryAmount multiplyAmount = oneDolar.multiply (0,25); MonetaryAmount divideAmount = oneDolar.divide (0,25); assertEquals ("USD", usd.toString ()); assertEquals ("1 USD", oneDolar.toString ()); assertEquals ("200,5 USD", fstAmtUSD.toString ()); assertEquals ("12 USD", moneyof.toString ()); assertEquals ("USD -199,5", oduzetiAmount.toString ()); assertEquals ("0,25 USD", multiplyAmount.toString ()); assertEquals ("4 USD", divideAmount.toString ()); }

8. Monetarno zaokruživanje

Monetarno zaokruživanje nije ništa drugo nego pretvorba iz iznosa neodređene preciznosti u zaokruženi iznos.

Koristit ćemo getDefaultRounding API koji pruža Monetarni klase za pretvorbu. Zadane vrijednosti zaokruživanja pruža valuta:

@Test javna praznina givenAmount_whenRounded_thanEquals () {MonetaryAmount fstAmtEUR = Monetary.getDefaultAmountFactory () .setCurrency ("EUR"). SetNumber (1.30473908) .create (); MonetaryAmount roundEUR = fstAmtEUR.with (Monetary.getDefaultRounding ()); assertEquals ("1,30473908 EUR", fstAmtEUR.toString ()); assertEquals ("1,3 EUR", roundEUR.toString ()); }

9. Pretvorba valuta

Konverzija valuta važan je aspekt poslovanja s novcem. Nažalost, ove pretvorbe imaju velik izbor različitih implementacija i slučajeva korištenja.

API se fokusira na uobičajene aspekte pretvorbe valuta na temelju izvora, ciljne valute i tečaja.

Pretvorba valuta ili pristup tečajevima mogu se parametrizirati:

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

Pretvorba je uvijek vezana uz valutu. MonetaryAmount može se jednostavno pretvoriti dodavanjem a Pretvorba valute do iznosa s metoda.

10. Oblikovanje valute

Oblikovanje omogućuje pristup formatima na temelju java.util.Locale. Suprotno JDK-u, formativači definirani ovim API-jem zaštićeni su nitima:

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

Ovdje koristimo unaprijed definirani format i izrađujemo prilagođeni format za naše valute. Korištenje standardnog formata jednostavno je koristeći oblik metode iz Monetarni formati razred. Definirali smo svoj prilagođeni format postavljajući svojstvo uzorka graditelja upita za format.

Kao i prije, jer je valuta uključena u rezultat, testiramo naše rezultate pomoću Žice:

@Test javna praznina givenAmount_whenCustomFormat_thanEquals () {MonetaryAmount oneDollar = Monetary.getDefaultAmountFactory () .setCurrency ("USD"). SetNumber (1) .create (); MonetaryAmountFormat customFormat = MonetaryFormats.getAmountFormat (AmountFormatQueryBuilder. Of (Locale.US) .set (CurrencyStyle.NAME) .set ("pattern", "00000.00 ¤"). Build ()); Niz customFormatted = customFormat.format (oneDollar); assertNotNull (customFormat); assertEquals ("1 USD", oneDollar.toString ()); assertEquals ("00001,00 američki dolar", prilagođeno formatirano); }

11. Sažetak

U ovom smo kratkom članku pokrili osnove Java novca i valute JSR.

Monetarne vrijednosti koriste se svugdje, a Java nudi da počinje podržavati i obrađivati ​​monetarne vrijednosti, aritmetiku ili pretvorbu valuta.

Kao i uvijek, kôd iz članka možete pronaći na Githubu.