设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客

Java 9中新的货币API

2015-1-9 09:00| 发布者: joejoe0332| 查看: 3806| 评论: 0|原作者: Java译站|来自: Java译站

摘要: 此前,Oracle公布Java 9首个增强计划集(众所周知的JEPs)确定会在2016年早些时候发布。而目前,JSR 354定义了一套新的Java货币API,计划会在Java 9中正式引入。JSR 354定义了一套新的Java货币API,计划会在Java 9中 ...
  此前,Oracle公布Java 9首个增强计划集(众所周知的JEPs)确定会在2016年早些时候发布。而目前,JSR 354定义了一套新的Java货币API,计划会在Java 9中正式引入。

  JSR 354定义了一套新的Java货币API,计划会在Java 9中正式引入。本文中我们将来看一下它的参考实现:JavaMoney的当前进展。


  正如我在之前那篇Java 8新的日期时间API一文中那样,本文主要也是通过一些代码来演示下新的API的用法 。


  在开始之前,我想先用一段话来简短地总结一下规范定义的这套新的API的用意何在:

对许多应用而言货币价值都是一个关键的特性,但JDK对此却几乎没有任何支持。严格来讲,现有的java.util.Currency类只是代表了当前ISO 4217货币的一个数据结构,但并没有关联的值或者自定义货币。JDK对货币的运算及转换也没有内建的支持,更别说有一个能够代表货币值的标准类型了。


  如果你用的是Maven的话,只需把下面的引用添加到工里面便能够体验下该参考实现的当前功能了:

  1. <dependency>  
  2.   <groupId>org.javamoney</groupId>  
  3.   <artifactId>moneta</artifactId>  
  4.   <version>0.9</version>  
  5. </dependency>  

规范中提到的类及接口都在javax.money.*包下面。

我们先从核心的两个接口CurrencyUnit与MonetaryAmount开始讲起。

CurrencyUnit及MonetaryAmount

CurrencyUnit代表的是货币。它有点类似于现在的java.util.Currency类,不同之处在于它支持自定义的实现。从规范的定义来看,java.util.Currency也是可以实现该接口的。CurrencyUnit的实例可以通过MonetaryCurrencies工厂来获取:

  1. // 根据货币代码来获取货币单位 CurrencyUnit euro = MonetaryCurrencies.getCurrency("EUR");  
  2.     CurrencyUnit usDollar = MonetaryCurrencies.getCurrency("USD"); // 根据国家及地区来获取货币单位  
  3.     CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN); CurrencyUnit  
  4.     canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);  
MontetaryAmount代表的是某种货币的具体金额。通常它都会与某个CurrencyUnit绑定。MontetaryAmount和CurrencyUnit一样,也是一个能支持多种实现的接口。CurrencyUnit与MontetaryAmount的实现必须是不可变,线程安全且可比较的。
  1. / get MonetaryAmount from CurrencyUnit  
  2. CurrencyUnit euro = MonetaryCurrencies.getCurrency("EUR");  
  3. MonetaryAmount fiveEuro = Money.of(5, euro);  
  4.    
  5. // get MonetaryAmount from currency code  
  6. MonetaryAmount tenUsDollar = Money.of(10"USD");  
  7.    
  8. // FastMoney is an alternative MonetaryAmount factory that focuses on performance  
  9. MonetaryAmount sevenEuro = FastMoney.of(7, euro);  

Money与FastMoney是JavaMoney库中MonetaryAmount的两种实现。Money是默认实现,它使用BigDecimal来存储金额。FastMoney是可选的另一个实现,它用long类型来存储金额。根据文档来看,FastMoney上的操作要比Money的快10到15倍左右。然而,FastMoney的金额大小与精度都受限于long类型。

注意了,这里的Money和FastMoney都是具体的实现类(它们在org.javamoney.moneta.*包下面,而不是javax.money.*)。如果你不希望指定具体类型的话,可以通过MonetaryAmountFactory来生成一个MonetaryAmount的实例:

  1. MonetaryAmount specAmount = MonetaryAmounts.getDefaultAmountFactory()  
  2.                 .setNumber(123.45) .setCurrency("USD") .create();  
当且仅当实现类,货币单位,以及数值全部相等时才认为这两个MontetaryAmount实例是相等的。 
  1. MonetaryAmount oneEuro = Money.of(1, MonetaryCurrencies.getCurrency("EUR"));  
  2. boolean isEqual = oneEuro.equals(Money.of(1"EUR")); // true  
  3. boolean isEqualFast = oneEuro.equals(FastMoney.of(1"EUR")); // false  
MonetaryAmount内包含丰富的方法,可以用来获取具体的货币,金额,精度等等: 
  1. MonetaryAmount monetaryAmount = Money.of(123.45, euro);  
  2. CurrencyUnit currency = monetaryAmount.getCurrency();  
  3. NumberValue numberValue = monetaryAmount.getNumber();  
  4.    
  5. int intValue = numberValue.intValue(); // 123  
  6. double doubleValue = numberValue.doubleValue(); // 123.45  
  7. long fractionDenominator = numberValue.getAmountFractionDenominator(); // 100  
  8. long fractionNumerator = numberValue.getAmountFractionNumerator(); // 45  
  9. int precision = numberValue.getPrecision(); // 5  
  10.    
  11. // NumberValue extends java.lang.Number.   
  12. // So we assign numberValue to a variable of type Number  
  13. Number number = numberValue;  

MonetaryAmount的使用

可以在MonetaryAmount上进行算术运算:

  1. MonetaryAmount twelveEuro = fiveEuro.add(sevenEuro); // "EUR 12"  
  2. MonetaryAmount twoEuro = sevenEuro.subtract(fiveEuro); // "EUR 2"  
  3. MonetaryAmount sevenPointFiveEuro = fiveEuro.multiply(1.5); // "EUR 7.5"  
  4.    
  5. // MonetaryAmount can have a negative NumberValue  
  6. MonetaryAmount minusTwoEuro = fiveEuro.subtract(sevenEuro); // "EUR -2"  
  7.    
  8. // some useful utility methods  
  9. boolean greaterThan = sevenEuro.isGreaterThan(fiveEuro); // true  
  10. boolean positive = sevenEuro.isPositive(); // true  
  11. boolean zero = sevenEuro.isZero(); // false  
  12.    
  13. // Note that MonetaryAmounts need to have the same CurrencyUnit to do mathematical operations  
  14. // this fails with: javax.money.MonetaryException: Currency mismatch: EUR/USD  
  15. fiveEuro.add(tenUsDollar);  
舍入操作是金额换算里面非常重要的一部分。MonetaryAmount可以使用舍入操作符来进行四舍五入: 
  1. CurrencyUnit usd = MonetaryCurrencies.getCurrency("USD");  
  2. MonetaryAmount dollars = Money.of(12.34567, usd);  
  3. MonetaryOperator roundingOperator = MonetaryRoundings.getRounding(usd);  
  4. MonetaryAmount roundedDollars = dollars.with(roundingOperator); // USD 12.35  

这里12.3456美金就会按当前货币默认的舍入规则来进行换算。

在操作MonetaryAmount集合时,有许多实用的工具方法可以用来进行过滤,排序以及分组。这些方法还可以与Java 8的流API一起配套使用。

看一下下面这个集合:

  1. List<MonetaryAmount> amounts = new ArrayList<>();  
  2. amounts.add(Money.of(2"EUR"));  
  3. amounts.add(Money.of(42"USD"));  
  4. amounts.add(Money.of(7"USD"));  
  5. amounts.add(Money.of(13.37"JPY"));  
  6. amounts.add(Money.of(18"USD"));  
我们可以根据CurrencyUnit来进行金额过滤: 
  1. CurrencyUnit yen = MonetaryCurrencies.getCurrency("JPY");  
  2. CurrencyUnit dollar = MonetaryCurrencies.getCurrency("USD");  
  3. // 根据货币过滤,只返回美金  
  4. // result is [USD 18, USD 7, USD 42]  
  5. List<MonetaryAmount> onlyDollar = amounts.stream()  
  6.     .filter(MonetaryFunctions.isCurrency(dollar))  
  7.     .collect(Collectors.toList());  
  8.    
  9. // 根据货币过滤,只返回美金和日元  
  10. // [USD 18, USD 7, JPY 13.37, USD 42]  
  11. List<MonetaryAmount> onlyDollarAndYen = amounts.stream()  
  12.     .filter(MonetaryFunctions.isCurrency(dollar, yen))  
  13.     .collect(Collectors.toList());  
我们还可以过滤出大于或小于某个阈值的金额:
  1. MonetaryAmount tenDollar = Money.of(10, dollar);  
  2.    
  3. // [USD 42, USD 18]  
  4. List<MonetaryAmount> greaterThanTenDollar = amounts.stream()  
  5.     .filter(MonetaryFunctions.isCurrency(dollar))  
  6.     .filter(MonetaryFunctions.isGreaterThan(tenDollar))  
  7.     .collect(Collectors.toList());  
排序也是类似的:
  1. // Sorting dollar values by number value  
  2. // [USD 7, USD 18, USD 42]  
  3. List<MonetaryAmount> sortedByAmount = onlyDollar.stream()  
  4.     .sorted(MonetaryFunctions.sortNumber())  
  5.     .collect(Collectors.toList());  
  6.    
  7. // Sorting by CurrencyUnit  
  8. // [EUR 2, JPY 13.37, USD 42, USD 7, USD 18]  
  9. List<MonetaryAmount> sortedByCurrencyUnit = amounts.stream()  
  10.     .sorted(MonetaryFunctions.sortCurrencyUnit())  
  11.     .collect(Collectors.toList());  
还有分组操作:
  1. // 按货币单位进行分组  
  2. // {USD=[USD 42, USD 7, USD 18], EUR=[EUR 2], JPY=[JPY 13.37]}  
  3. Map<CurrencyUnit, List<MonetaryAmount>> groupedByCurrency = amounts.stream()  
  4.     .collect(MonetaryFunctions.groupByCurrencyUnit());  
  5.    
  6. // 分组并进行汇总  
  7. Map<CurrencyUnit, MonetarySummaryStatistics> summary = amounts.stream()  
  8.     .collect(MonetaryFunctions.groupBySummarizingMonetary()).get();  
  9.    
  10. // get summary for CurrencyUnit USD  
  11. MonetarySummaryStatistics dollarSummary = summary.get(dollar);  
  12. MonetaryAmount average = dollarSummary.getAverage(); // "USD 22.333333333333333333.."  
  13. MonetaryAmount min = dollarSummary.getMin(); // "USD 7"  
  14. MonetaryAmount max = dollarSummary.getMax(); // "USD 42"  
  15. MonetaryAmount sum = dollarSummary.getSum(); // "USD 67"  
  16. long count = dollarSummary.getCount(); // 3  


酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部