javascript
研究Java 9 Money and Currency API(JSR 354)
JSR 354定義了一個用于處理貨幣和貨幣的新Java API,計劃將其包含在Java 9中。在本文中,我們將研究參考實現的當前狀態:
JavaMoney 。
就像我關于Java 8日期/時間API的帖子一樣,該帖子將主要由顯示新API的代碼驅動。
但是在開始之前,我想引用一下規范中的一小部分,以總結一下此新API的動機:
貨幣價值是許多應用程序的關鍵功能,但是JDK提供的支持很少或沒有。 現有的java.util.Currency類嚴格來說是一種用于表示當前ISO 4217貨幣的結構,但不是關聯值或自定義貨幣。 JDK還不支持貨幣算術或貨幣轉換,也不支持代表貨幣金額的標準值類型。
如果使用Maven,則可以通過將以下依賴項添加到項目中來輕松嘗試參考實現的當前狀態:
<dependency><groupId>org.javamoney</groupId><artifactId>moneta</artifactId><version>0.9</version> </dependency>所有規范類和接口都位于javax.money。*包中。
我們將從兩個核心接口CurrencyUnit和MonetaryAmount開始。 之后,我們將研究匯率,貨幣轉換和格式。
貨幣單位和貨幣金額
CurrencyUnit為貨幣建模。 CurrencyUnit與現有的java.util.Currency類非常相似,不同之處在于它允許自定義實現。 根據規范,java.util.Currency應該可以實現CurrencyUnit。 可以使用MonetaryCurrencies工廠獲取CurrencyUnit實例:
//?getting?CurrencyUnits?by?currency?code CurrencyUnit?euro?=?MonetaryCurrencies.getCurrency("EUR"); CurrencyUnit?usDollar?=?MonetaryCurrencies.getCurrency("USD");//?getting?CurrencyUnits?by?locale CurrencyUnit?yen?=?MonetaryCurrencies.getCurrency(Locale.JAPAN); CurrencyUnit?canadianDollar?=?MonetaryCurrencies.getCurrency(Locale.CANADA);MontetaryAmount表示貨幣金額的具體數字表示。 MonetaryAmount始終綁定到CurrencyUnit。 與CurrencyUnit一樣,MonetaryAmount是支持不同實現的接口。 CurrencyUnit和MonetaryAmount實現必須是不可變的,線程安全的,可序列化的和可比較的。
//?get?MonetaryAmount?from?CurrencyUnit CurrencyUnit?euro?=?MonetaryCurrencies.getCurrency("EUR"); MonetaryAmount?fiveEuro?=?Money.of(5,?euro);//?get?MonetaryAmount?from?currency?code MonetaryAmount?tenUsDollar?=?Money.of(10,?"USD");//?FastMoney?is?an?alternative?MonetaryAmount?factory?that?focuses?on?performance MonetaryAmount?sevenEuro?=?FastMoney.of(7,?euro);Money和FastMoney是JavaMoney的兩個MonetaryAmount實現。 Money是使用BigDecimal存儲數字值的默認實現。 FastMoney是一種將金額存儲在長字段中的替代實現。 根據文檔,與Money相比,FastMoney的運行速度快10到15倍。 但是,FastMoney受long類型的大小和精度的限制。
請注意,Money和FastMoney是實現特定的類(位于org.javamoney.moneta。*而不是javax.money。*中)。 如果要避免實現特定的類,則必須獲取MonetaryAmountFactory來創建MonetaryAmount實例:
MonetaryAmount?specAmount?=?MonetaryAmounts.getDefaultAmountFactory().setNumber(123.45).setCurrency("USD").create();如果實現類,貨幣單位和數值相等,則認為兩個MontetaryAmount實例相等:
MonetaryAmount?oneEuro?=?Money.of(1,?MonetaryCurrencies.getCurrency("EUR")); boolean?isEqual?=?oneEuro.equals(Money.of(1,?"EUR"));?//?true boolean?isEqualFast?=?oneEuro.equals(FastMoney.of(1,?"EUR"));?//?falseMonetaryAmount具有多種方法,可用于訪問分配的貨幣,數字量,其精度等:
MonetaryAmount?monetaryAmount?=?Money.of(123.45,?euro); CurrencyUnit?currency?=?monetaryAmount.getCurrency(); NumberValue?numberValue?=?monetaryAmount.getNumber();int?intValue?=?numberValue.intValue();?//?123 double?doubleValue?=?numberValue.doubleValue();?//?123.45 long?fractionDenominator?=?numberValue.getAmountFractionDenominator();?//?100 long?fractionNumerator?=?numberValue.getAmountFractionNumerator();?//?45 int?precision?=?numberValue.getPrecision();?//?5//?NumberValue?extends?java.lang.Number.? //?So?we?assign?numberValue?to?a?variable?of?type?Number Number?number?=?numberValue;使用MonetaryAmounts
可以使用MonetaryAmount執行數學運算:
MonetaryAmount?twelveEuro?=?fiveEuro.add(sevenEuro);?//?"EUR?12" MonetaryAmount?twoEuro?=?sevenEuro.subtract(fiveEuro);?//?"EUR?2" MonetaryAmount?sevenPointFiveEuro?=?fiveEuro.multiply(1.5);?//?"EUR?7.5"//?MonetaryAmount?can?have?a?negative?NumberValue MonetaryAmount?minusTwoEuro?=?fiveEuro.subtract(sevenEuro);?//?"EUR?-2"//?some?useful?utility?methods boolean?greaterThan?=?sevenEuro.isGreaterThan(fiveEuro);?//?true boolean?positive?=?sevenEuro.isPositive();?//?true boolean?zero?=?sevenEuro.isZero();?//?false//?Note?that?MonetaryAmounts?need?to?have?the?same?CurrencyUnit?to?do?mathematical?operations //?this?fails?with:?javax.money.MonetaryException:?Currency?mismatch:?EUR/USD fiveEuro.add(tenUsDollar);四舍五入是使用金錢時的另一個重要部分。 可以使用舍入運算符舍入MonetaryAmount:
CurrencyUnit?usd?=?MonetaryCurrencies.getCurrency("USD"); MonetaryAmount?dollars?=?Money.of(12.34567,?usd); MonetaryOperator?roundingOperator?=?MonetaryRoundings.getRounding(usd); MonetaryAmount?roundedDollars?=?dollars.with(roundingOperator);?//?USD?12.35在這里,12.3456美元使用該貨幣的默認舍入取整。
當使用MonetaryAmounts的集合時,可以使用一些不錯的實用程序方法進行過濾,排序和分組。 這些方法可以與Java 8 Stream API一起使用。
考慮以下集合:
List<MonetaryAmount>?amounts?=?new?ArrayList<>(); amounts.add(Money.of(2,?"EUR")); amounts.add(Money.of(42,?"USD")); amounts.add(Money.of(7,?"USD")); amounts.add(Money.of(13.37,?"JPY")); amounts.add(Money.of(18,?"USD"));現在,我們可以按CurrencyUnit過濾金額:
CurrencyUnit?yen?=?MonetaryCurrencies.getCurrency("JPY"); CurrencyUnit?dollar?=?MonetaryCurrencies.getCurrency("USD");//?filter?by?currency,?get?only?dollars //?result?is?[USD?18,?USD?7,?USD?42] List<MonetaryAmount>?onlyDollar?=?amounts.stream().filter(MonetaryFunctions.isCurrency(dollar)).collect(Collectors.toList());//?filter?by?currency,?get?only?dollars?and?yen //?[USD?18,?USD?7,?JPY?13.37,?USD?42] List<MonetaryAmount>?onlyDollarAndYen?=?amounts.stream().filter(MonetaryFunctions.isCurrency(dollar,?yen)).collect(Collectors.toList());我們還可以過濾出小于或大于特定閾值的MonetaryAmounts:
MonetaryAmount?tenDollar?=?Money.of(10,?dollar);//?[USD?42,?USD?18] List<MonetaryAmount>?greaterThanTenDollar?=?amounts.stream().filter(MonetaryFunctions.isCurrency(dollar)).filter(MonetaryFunctions.isGreaterThan(tenDollar)).collect(Collectors.toList());排序的工作方式類似:
//?Sorting?dollar?values?by?number?value //?[USD?7,?USD?18,?USD?42] List<MonetaryAmount>?sortedByAmount?=?onlyDollar.stream().sorted(MonetaryFunctions.sortNumber()).collect(Collectors.toList());//?Sorting?by?CurrencyUnit //?[EUR?2,?JPY?13.37,?USD?42,?USD?7,?USD?18] List<MonetaryAmount>?sortedByCurrencyUnit?=?amounts.stream().sorted(MonetaryFunctions.sortCurrencyUnit()).collect(Collectors.toList());分組功能:
//?Grouping?by?CurrencyUnit //?{USD=[USD?42,?USD?7,?USD?18],?EUR=[EUR?2],?JPY=[JPY?13.37]} Map<CurrencyUnit,?List<MonetaryAmount>>?groupedByCurrency?=?amounts.stream().collect(MonetaryFunctions.groupByCurrencyUnit());//?Grouping?by?summarizing?MonetaryAmounts Map<CurrencyUnit,?MonetarySummaryStatistics>?summary?=?amounts.stream().collect(MonetaryFunctions.groupBySummarizingMonetary()).get();//?get?summary?for?CurrencyUnit?USD MonetarySummaryStatistics?dollarSummary?=?summary.get(dollar); MonetaryAmount?average?=?dollarSummary.getAverage();?//?"USD?22.333333333333333333.." MonetaryAmount?min?=?dollarSummary.getMin();?//?"USD?7" MonetaryAmount?max?=?dollarSummary.getMax();?//?"USD?42" MonetaryAmount?sum?=?dollarSummary.getSum();?//?"USD?67" long?count?=?dollarSummary.getCount();?//?3MonetaryFunctions還提供歸約函數,可用于獲取MonetaryAmount集合的最大值,最小值和總和:
List<MonetaryAmount>?amounts?=?new?ArrayList<>(); amounts.add(Money.of(10,?"EUR")); amounts.add(Money.of(7.5,?"EUR")); amounts.add(Money.of(12,?"EUR"));Optional<MonetaryAmount>?max?=?amounts.stream().reduce(MonetaryFunctions.max());?//?"EUR?7.5" Optional<MonetaryAmount>?min?=?amounts.stream().reduce(MonetaryFunctions.min());?//?"EUR?12" Optional<MonetaryAmount>?sum?=?amounts.stream().reduce(MonetaryFunctions.sum());?//?"EUR?29.5"自定義MonetaryAmount操作
MonetaryAmount提供了一個很好的擴展點,稱為MonetaryOperator。 MonetaryOperator是一個功能接口,它將MonetaryAmount作為輸入并根據輸入創建一個新的MonetaryAmount。
//?A?monetary?operator?that?returns?10%?of?the?input?MonetaryAmount //?Implemented?using?Java?8?Lambdas MonetaryOperator?tenPercentOperator?=?(MonetaryAmount?amount)?->?{BigDecimal?baseAmount?=?amount.getNumber().numberValue(BigDecimal.class);BigDecimal?tenPercent?=?baseAmount.multiply(new?BigDecimal("0.1"));return?Money.of(tenPercent,?amount.getCurrency()); };MonetaryAmount?dollars?=?Money.of(12.34567,?"USD");//?apply?tenPercentOperator?to?MonetaryAmount MonetaryAmount?tenPercentDollars?=?dollars.with(tenPercentOperator);?//?USD?1.234567一些標準API功能被實現為MonetaryOperator。 例如,我們在上面看到的舍入功能被實現為MonetaryOperator。
匯率
可以使用ExchangeRateProvider獲得貨幣匯率。 JavaMoney帶有多個不同的ExchangeRateProvider實現。 兩個最重要的實現是ECBCurrentRateProvider和IMFRateProvider。
ECBCurrentRateProvider查詢歐洲中央銀行(ECB)數據供稿以獲取當前匯率,而IMFRateProvider使用國際貨幣基金組織(IMF)轉換率。
//?get?the?default?ExchangeRateProvider?(CompoundRateProvider) ExchangeRateProvider?exchangeRateProvider?=?MonetaryConversions.getExchangeRateProvider();//?get?the?names?of?the?default?provider?chain //?[IDENT,?ECB,?IMF,?ECB-HIST] List<String>?defaultProviderChain?=?MonetaryConversions.getDefaultProviderChain();//?get?a?specific?ExchangeRateProvider?(here?ECB) ExchangeRateProvider?ecbExchangeRateProvider?=?MonetaryConversions.getExchangeRateProvider("ECB");如果未請求特定的ExchangeRateProvider,則將返回CompoundRateProvider。 CompoundRateProvider將匯率請求委托給一系列ExchangeRateProviders,并從第一個返回足夠結果的提供程序返回結果。
//?get?the?exchange?rate?from?euro?to?us?dollar ExchangeRate?rate?=?exchangeRateProvider.getExchangeRate("EUR",?"USD");NumberValue?factor?=?rate.getFactor();?//?1.2537?(at?time?writing) CurrencyUnit?baseCurrency?=?rate.getBaseCurrency();?//?EUR CurrencyUnit?targetCurrency?=?rate.getCurrency();?//?USD貨幣轉換
貨幣之間的轉換是通過從ExchangeRateProviders獲得的CurrencyConversions完成的:
//?get?the?CurrencyConversion?from?the?default?provider?chain CurrencyConversion?dollarConversion?=?MonetaryConversions.getConversion("USD");//?get?the?CurrencyConversion?from?a?specific?provider CurrencyConversion?ecbDollarConversion?=?ecbExchangeRateProvider.getCurrencyConversion("USD");MonetaryAmount?tenEuro?=?Money.of(10,?"EUR");//?convert?10?euro?to?us?dollar? MonetaryAmount?inDollar?=?tenEuro.with(dollarConversion); //?"USD?12.537"?(at?the?time?writing)請注意,CurrencyConversion實現MonetaryOperator。 像其他運算符一樣,可以使用MonetaryAmount.with()來應用它。
格式化和解析
MonetaryAmounts可以使用MonetaryAmountFormat從字符串解析/格式化為字符串:
//?formatting?by?locale?specific?formats MonetaryAmountFormat?germanFormat?=?MonetaryFormats.getAmountFormat(Locale.GERMANY); MonetaryAmountFormat?usFormat?=?MonetaryFormats.getAmountFormat(Locale.CANADA);MonetaryAmount?amount?=?Money.of(12345.67,?"USD");String?usFormatted?=?usFormat.format(amount);?//?"USD12,345.67" String?germanFormatted?=?germanFormat.format(amount);?//?12.345,67?USD//?A?MonetaryAmountFormat?can?also?be?used?to?parse?MonetaryAmounts?from?strings MonetaryAmount?parsed?=?germanFormat.parse("12,4?USD");使用AmountFormatQueryBuilder可以創建自定義格式:
//?Creating?a?custom?MonetaryAmountFormat MonetaryAmountFormat?customFormat?=?MonetaryFormats.getAmountFormat(AmountFormatQueryBuilder.of(Locale.US).set(CurrencyStyle.NAME).set("pattern",?"00,00,00,00.00?¤").build());//?results?in?"00,01,23,45.67?US?Dollar" String?formatted?=?customFormat.format(amount);請注意,¤符號(\ u00A)用作模式字符串內的貨幣占位符。
摘要
我們研究了新的Money and Currency API的許多部分。 該實現看起來已經很可靠了(但是肯定需要更多文檔)。 我期待在Java 9中看到此API!
- 您可以在GitHub上找到此處顯示的所有示例。
翻譯自: https://www.javacodegeeks.com/2014/12/looking-into-the-java-9-money-and-currency-api-jsr-354.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的研究Java 9 Money and Currency API(JSR 354)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 楚乔传一共多少集 楚乔传简单介绍
- 下一篇: Apache TomEE(和Tomcat