1概要


JSR 354

– “ Currency and Money”は、Javaの通貨と金額の標準化を扱います。

その目標は、Javaエコシステムに柔軟で拡張可能なAPIを追加し、金額の操作をより簡単かつ安全にすることです。

  • JSRはJDK 9には組み込まれていませんが、将来のJDKリリースの候補になります。


2セットアップ

まず、

pom.xml

ファイルに依存関係を定義しましょう。

<dependency>
    <groupId>org.javamoney</groupId>
    <artifactId>moneta</artifactId>
    <version>1.1</version>
</dependency>

依存関係の最新版はhttps://search.maven.org/classic/#search%7C1%7Cg%3A%22org.javamoney%22%20AND%20a%3A%22moneta%22[here]で確認できます。

** 3 JSR-354の機能+

**

“ Currency and Money” APIの目的は次のとおりです。

  • 金額を処理および計算するためのAPIを提供する

  • 通貨と金額を表すクラスを次のように定義します。

通貨の丸め
** 為替レートを扱う

  • 通貨と金額のフォーマットと解析を処理する


4モデル

次の図に、JSR-354仕様の主なクラスを示します。

リンク:/uploads/javax-monetary3-1.png%20395w[]

このモデルには、次のセクションで説明する2つの主要なインタフェース

CurrencyUnit

と__MonetaryAmountがあります。


5

CurrencyUnit



CurrencyUnit

は、通貨の最小限のプロパティをモデル化します。そのインスタンスは

Monetary.getCurrency

メソッドを使って取得できます。

@Test
public void givenCurrencyCode__whenString__thanExist() {
    CurrencyUnit usd = Monetary.getCurrency("USD");

    assertNotNull(usd);
    assertEquals(usd.getCurrencyCode(), "USD");
    assertEquals(usd.getNumericCode(), 840);
    assertEquals(usd.getDefaultFractionDigits(), 2);
}

通貨の

String

表現を使用して

CurrencyUnit

を作成します。これは、存在しないコードで通貨を作成しようとする状況につながる可能性があります。存在しないコードで通貨を作成すると、

UnknownCurrency

例外が発生します。

@Test(expected = UnknownCurrencyException.class)
public void givenCurrencyCode__whenNoExist__thanThrowsError() {
    Monetary.getCurrency("AAA");
}


6.

MonetaryAmount



MonetaryAmount

は金額の数値表現です。これは常に

CurrencyUnit

と関連付けられており、通貨の通貨表記を定義します。

金額は、具体的な各ユースケースで定義された金額表現要件の動作に焦点を当てて、さまざまな方法で実装できます。例えば。

Money



FastMoney

は、

MonetaryAmount

インターフェースの実装です。


FastMoney

は、

long

を数値表現として使用して

MonetaryAmount

を実装し、精度を犠牲にして

BigDecimal

より高速です。パフォーマンスが必要なときに使用できます。精度は問題になりません。

一般的なインスタンスは、デフォルトのファクトリを使って作成することができます。

MonetaryAmount

インスタンスを取得するさまざまな方法を示しましょう。

@Test
public void 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


通貨演算



Money



FastMoney

の間で通貨演算を実行できますが、これら2つのクラスのインスタンスを組み合わせるときは注意が必要です。

たとえば、1つのEuroインスタンスの

FastMoney

を1つのEuroインスタンスの

Money

と比較すると、結果は同じではありません。

@Test
public void 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")));
}


MonetaryAmount

クラスによって提供されるメソッドを使用して、加算、減算、乗算、除算、およびその他の通貨算術演算を実行できます。

数値間の算術演算が使用する数値表現型の機能を上回る場合、算術演算では

ArithmeticException

がスローされます。たとえば、1から3で除算しようとすると、結果が無限大になるため

ArithmeticException

が発生します。

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

金額を足したり引いたりするときは、金額間の演算を実行するために両方の金額が同じ通貨を持つようにする必要があるため、

MonetaryAmount

のインスタンスであるパラメータを使用することをお勧めします。


7.1. 金額の計算

金額の合計は複数の方法で計算できます。1つの方法は、単に金額を次のように連結することです。

@Test
public void 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());
}

連鎖は減算にも適用できます。

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

掛け算:

MonetaryAmount multiplyAmount = oneDolar.multiply(0.25);

または分割:

MonetaryAmount divideAmount = oneDolar.divide(0.25);

結果に通貨も含まれているため、文字列を使用していることから、文字列を使用して算術結果を比較しましょう。

@Test
public void 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").subtract(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通貨丸め

通貨の丸めは、未確定の精度を持つ金額から丸められた金額への変換に他なりません。

変換には

Monetary

クラスが提供する

getDefaultRounding

APIを使用します。デフォルトの丸め値は通貨によって提供されます。

@Test
public void 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通貨換算

通貨換算は、お金を扱う上で重要な側面です。

残念ながら、これらの変換には多種多様な実装とユースケースがあります。

APIは、ソース、ターゲット通貨、および為替レートに基づく通貨変換の一般的な側面に焦点を当てています。

通貨換算または為替レートのアクセスは、パラメータ化することができます。

@Test
public void givenAmount__whenConversion__thenNotNull() {
    MonetaryAmount oneDollar = Monetary.getDefaultAmountFactory().setCurrency("USD")
      .setNumber(1).create();

    CurrencyConversion conversionEUR = MonetaryConversions.getConversion("EUR");

    MonetaryAmount convertedAmountUSDtoEUR = oneDollar.with(conversionEUR);

    assertEquals("USD 1", oneDollar.toString());
    assertNotNull(convertedAmountUSDtoEUR);
}

変換は常に通貨にバインドされています。

MonetaryAmount

は、

CurrencyConversion

をamountの

with

メソッドに渡すことで簡単に変換できます。


10通貨フォーマット

フォーマットにより、

java.util.Locale

に基づくフォーマットにアクセスできます。

JDKとは反対に、このAPIで定義されているフォーマッタはスレッドセーフです。

@Test
public void givenLocale__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);
}

ここでは、事前定義されたフォーマットを使用して通貨用のカスタムフォーマットを作成しています。標準フォーマットの使用は

MonetaryFormats

クラスのメソッドフォーマットを使用することで簡単です。私達は私達のカスタムフォーマット設定フォーマットクエリービルダーのパターンプロパティを定義しました。

通貨は結果に含まれているので、以前と同様に

Strings

を使用して結果をテストします。

@Test
public void 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());
    String customFormatted = customFormat.format(oneDollar);

    assertNotNull(customFormat);
    assertEquals("USD 1", oneDollar.toString());
    assertEquals("00001.00 US Dollar", customFormatted);
}


11概要

この簡単な記事では、Java Money&Currency JSRの基本について説明しました。

金銭的価値は至る所で使用されており、Javaが提供するものは金銭的価値、算術または通貨変換をサポートし、処理し始めています。

いつものように、あなたは記事https://github.com/eugenp/tutorials/tree/master/core-java[over on Github]からコードを見つけることができます。