中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Java 9中新的貨幣API

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

  JSR 354定義了一套新的Java貨幣API,計劃會在Java 9中正式引入。本文中我們將來看一下它的參考實現(xiàn):JavaMoney的當前進展。

  正如我在之前那篇Java 8新的日期時間API一文中那樣,本文主要也是通過一些代碼來演示下新的API的用法 。

  在開始之前,我想先用一段話來簡短地總結(jié)一下規(guī)范定義的這套新的API的用意何在:

對許多應(yīng)用而言貨幣價值都是一個關(guān)鍵的特性,但JDK對此卻幾乎沒有任何支持。嚴格來講,現(xiàn)有的java.util.Currency類只是代表了當前ISO 4217貨幣的一個數(shù)據(jù)結(jié)構(gòu),但并沒有關(guān)聯(lián)的值或者自定義貨幣。JDK對貨幣的運算及轉(zhuǎn)換也沒有內(nèi)建的支持,更別說有一個能夠代表貨幣值的標準類型了。

  如果你用的是Maven的話,只需把下面的引用添加到工里面便能夠體驗下該參考實現(xiàn)的當前功能了:

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

  規(guī)范中提到的類及接口都在javax.money.*包下面。

  我們先從核心的兩個接口CurrencyUnit與MonetaryAmount開始講起。

  CurrencyUnit及MonetaryAmount

  CurrencyUnit代表的是貨幣。它有點類似于現(xiàn)在的java.util.Currency類,不同之處在于它支持自定義的實現(xiàn)。從規(guī)范的定義來看,java.util.Currency也是可以實現(xiàn)該接口的。CurrencyUnit的實例可以通過MonetaryCurrencies工廠來獲取:

// 根據(jù)貨幣代碼來獲取貨幣單位 CurrencyUnit euro = MonetaryCurrencies.getCurrency("EUR");
    CurrencyUnit usDollar = MonetaryCurrencies.getCurrency("USD"); // 根據(jù)國家及地區(qū)來獲取貨幣單位
    CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN); CurrencyUnit
    canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);

  MontetaryAmount代表的是某種貨幣的具體金額。通常它都會與某個CurrencyUnit綁定。

  MontetaryAmount和CurrencyUnit一樣,也是一個能支持多種實現(xiàn)的接口。

  CurrencyUnit與MontetaryAmount的實現(xiàn)必須是不可變,線程安全且可比較的。

/ 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的兩種實現(xiàn)。Money是默認實現(xiàn),它使用BigDecimal來存儲金額。FastMoney是可選的另一個實現(xiàn),它用long類型來存儲金額。根據(jù)文檔來看,F(xiàn)astMoney上的操作要比Money的快10到15倍左右。然而,F(xiàn)astMoney的金額大小與精度都受限于long類型。

  注意了,這里的Money和FastMoney都是具體的實現(xiàn)類(它們在org.javamoney.moneta.*包下面,而不是javax.money.*)。如果你不希望指定具體類型的話,可以通過MonetaryAmountFactory來生成一個MonetaryAmount的實例:

MonetaryAmount specAmount = MonetaryAmounts.getDefaultAmountFactory()
                .setNumber(123.45) .setCurrency("USD") .create();

  當且僅當實現(xiàn)類,貨幣單位,以及數(shù)值全部相等時才認為這兩個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")); // false

  MonetaryAmount內(nèi)包含豐富的方法,可以用來獲取具體的貨幣,金額,精度等等:

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;

  MonetaryAmount的使用

  可以在MonetaryAmount上進行算術(shù)運算: 

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美金就會按當前貨幣默認的舍入規(guī)則來進行換算。

  在操作MonetaryAmount集合時,有許多實用的工具方法可以用來進行過濾,排序以及分組。這些方法還可以與Java 8的流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"));

  我們可以根據(jù)CurrencyUnit來進行金額過濾: 

CurrencyUnit yen = MonetaryCurrencies.getCurrency("JPY");
CurrencyUnit dollar = MonetaryCurrencies.getCurrency("USD");
// 根據(jù)貨幣過濾,只返回美金
// result is [USD 18, USD 7, USD 42]
List<MonetaryAmount> onlyDollar = amounts.stream()
    .filter(MonetaryFunctions.isCurrency(dollar))
    .collect(Collectors.toList());
 
// 根據(jù)貨幣過濾,只返回美金和日元
// [USD 18, USD 7, JPY 13.37, USD 42]
List<MonetaryAmount> onlyDollarAndYen = amounts.stream()
    .filter(MonetaryFunctions.isCurrency(dollar, yen))
    .collect(Collectors.toList());

  我們還可以過濾出大于或小于某個閾值的金額:

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());

  還有分組操作:

// 按貨幣單位進行分組
// {USD=[USD 42, USD 7, USD 18], EUR=[EUR 2], JPY=[JPY 13.37]}
Map<CurrencyUnit, List<MonetaryAmount>> groupedByCurrency = amounts.stream()
    .collect(MonetaryFunctions.groupByCurrencyUnit());
 
// 分組并進行匯總
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(); // 3

  MonetaryFunctions還提供了歸約函數(shù),可以用來獲取最大值,最小值,以及求和:

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()); //

  自定義的MonetaryAmount操作

  MonetaryAmount還提供了一個非常友好的擴展點叫作MonetaryOperator。MonetaryOperator是一個函數(shù)式接口,它接收一個MonetaryAmount入?yún)⒉⒎祷匾粋新的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的接口來實現(xiàn)的。比方說,前面看到的舍入操作就是以MonetaryOperator接口的形式來提供的。

  匯率

  貨幣兌換率可以通過ExchangeRateProvider來獲取。JavaMoney自帶了多個不同的ExchangeRateProvider的實現(xiàn)。其中最重要的兩個是ECBCurrentRateProvider與 IMFRateProvider。

  ECBCurrentRateProvider查詢的是歐洲中央銀行(European Central Bank,ECB)的數(shù)據(jù)而IMFRateProvider查詢的是國際貨幣基金組織(International Monetary Fund,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會將匯率轉(zhuǎn)換請求委派給一個ExchangeRateProvider鏈并將第一個返回準確結(jié)果的提供商的數(shù)據(jù)返回。

// 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

  貨幣轉(zhuǎn)換

  不同貨幣間的轉(zhuǎn)換可以通過ExchangeRateProvider返回的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也實現(xiàn)了MonetaryOperator接口。正如其它操作一樣,它也能通過MonetaryAmount.with()方法來調(diào)用。

  格式化及解析

  MonetaryAmount可以通過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);

  注意,這里的¤符號在模式串中是作為貨幣的占位符。

  總結(jié)

  新的貨幣API這里已經(jīng)介紹得差不多了。并且目前它的實現(xiàn)也已經(jīng)相對穩(wěn)定了(但還需要多補充些文檔)。期待能在Java 9中看到這套新的接口!

  上述示例可在Github中下載到。

  原文出處:Michael Scharhag

標簽: isp 安全 代碼

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。

上一篇:2014 Java發(fā)生的5件大事

下一篇:Android為何比iOS卡?論1G內(nèi)存的使用