jsr 269 api_研究Java 9 Money and Currency API(JSR 354)

jsr 269 api

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")); // false

MonetaryAmount具有多种方法,可用于访问分配的货币,数字量,其精度等:

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

MonetaryFunctions还提供归约函数,可用于获取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

jsr 269 api

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338733.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python程序调试题_关于python程序调试问题,一个文件计算的问题

那位大神帮小弟看下这段代码有什么需要改进的没有。程序要求为&#xff1a;程序主要内容是&#xff1a;大地坐标经纬度的格式转换问题&#xff0c;例如12030′30″转换为120.50833333&#xff0c;并且可以互换&#xff0c;这样的程序。...那位大神帮小弟看下这段代码有什么需要…

C语言 函数

定义函数在 C 语言中&#xff0c;函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分&#xff1a;返回类型&#xff1a;一个函数可以返回一个值。return_type 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值&#xff0c;在这种情况下&#xff…

cassandra 入门_Apache Cassandra和Java入门(第二部分)

cassandra 入门要求 要遵循本教程&#xff0c;您应该已经有一个正在运行的Cassandra实例&#xff08; 一个小型集群会很好 &#xff0c;但不是必需的&#xff09;&#xff0c;已安装Datastax Java驱动程序&#xff08; 请参阅第I部分 &#xff09;&#xff0c;并且已经在这里进…

蓝桥杯 java 组素数,2018 蓝桥杯省赛 B 组模拟赛(五) B 结果填空:素数个数

对0,1,2,3,4,5,6,7进行全排列&#xff0c;需要注意的是0不能开头&#xff0c;所以我直接让初始值设为1,0,2,3,4,5,6,7&#xff0c;这样就避免了0开头的情况。对于每一次去判断是不是素数的话会有点浪费时间&#xff0c;所以可以用素数打表。实现代码&#xff1a;#include using…

自适应 幻灯片代码 app_字节跳动 To B 再添一员,将推出飞书文档独立App | 36氪独家...

不只是功能点的延伸&#xff0c;以 C 端打 B 端&#xff0c;是字节跳动推出“飞书文档”的另一体现。文&#xff5c;苏建勋头图来源| IC photo据36氪获悉&#xff0c;字节跳动旗下移动办公软件“飞书”将于近期推出独立 App “飞书文档”。这是继2月底&#xff0c;字节跳动推出…

听说高手都用记事本写C语言代码?

坊间传闻高手都喜欢用记事本写代码&#xff0c;那么问题来了&#xff0c;我们以C语言为例&#xff0c;如何用记事本编译运行呢&#xff1f;其实最简单的方式就是安装GCC编译器&#xff0c;在记事本编写C语言程序&#xff0c;然后再在命令行用GCC编译运行&#xff0c;下面我简单…

jface_使用JFace Viewer延迟获取模型元素

jfaceEclipse JFace Viewers显示的模型元素有时需要花费大量时间来加载。 因此&#xff0c; 工作台提供了IDeferredWorkbenchAdapter类型以在后台获取此类模型元素。 不幸的是&#xff0c;似乎仅通过DeferredTreeContentManager派生的AbstractTreeViewer支持此机制。 因此&…

php第一课,[php第一课]php简介

学习php前提&#xff1a;应有html与css知识1、php简介[1]php是一种开源通用服务器端脚本语言。[2]php&#xff1a;hypertext preprocessor&#xff0c;译名为超文本预处理器[3]在服务器上执行[4]php文件&#xff1a;{1}php文件包含文本、html、js、php代码{2}服务器上运行&…

python省略_在python中如何连接用省略号(…)分隔的连续行

您只需&#xff1a;delim ...text This is single line.This is second long line... continue from previous line.This third single line.# here were building a list containing each line# well clean up the leading and trailing whitespace# by mapping Pythons str…

C语言边角料:结构体中指针类型的成员变量,它的类型重要吗?

一、前言昨天在编译代码的时候&#xff0c;之前一直OK的一个地方&#xff0c;却突然出现了好几个 Warning!本着强迫症要消灭一切警告的做法&#xff0c;最终定位到&#xff1a;是结构体内部&#xff0c; 指向结构体类型的指针成员变量导致的问题。这个问题&#xff0c;也许永远…

oracle 11g b表空间什么情况下自动增加,Oracle 11g表空间——创建和扩展(永久)表空间...

Oracle 11g表空间——创建和扩展(永久)表空间本文内容创建(永久)表空间查看表空间扩展表空间创建(永久)表空间Oracle 按照区和段空间进行管理表空间。区管理方式 - 针对区的分配方式的不同&#xff0c;有两种方式&#xff1a;字典管理方式(dictionary-managed tablespace&#…

python rsa 公钥解密_python利用rsa库做公钥解密的方法教程

前言对于RSA的解密&#xff0c;即密文的数字的 D 次方求mod N 即可&#xff0c;即密文和自己做 D 次乘法&#xff0c;再对结果除以 N 求余数即可得到明文。D 和 N 的组合就是私钥(private key)。算法的加密和解密还是很简单的&#xff0c;可是公钥和私钥的生成算法却不是随意的…

oracle 11g release2版本jdbc,Oracle发布JDeveloper11gRelease2更新版

Oracle在周二的时候发布了JDeveloper IDE升级版JDeveloper 11g Release 2&#xff0c;该版本支持JSF 2.0技术和模块化的服务端Web UI开发&#xff1b;另外该版本在启动时间上和运行性能上也有很大改善&#xff0c;因为整个IDE重新架构了&#xff0c;基于OSGi后端结构&#xff0…

C语言:--位域和内存对齐

位域位域是指信息在保存时&#xff0c;并不需要占用一个完整的字节&#xff0c;而只需要占几个或一个二进制位。为了节省空间&#xff0c;C语言提供了一种数据结构&#xff0c;叫“位域”或“位段”。“位域“是把一个字节中的二进位划分为几个不同的区域&#xff0c;并说明每个…

python页面驱动mxd_如何利用python 批量导出mxd至jpg

展开全部你好&#xff0c;arcpy.mapping提供了如下的函32313133353236313431303231363533e78988e69d8331333335313835数&#xff1a;arcpy.mapping 函数AddLayer(data_frame, add_layer, {add_position})AddLayerToGroup(data_frame, target_group_layer, add_layer, {add_posi…

junit rule_使用@Rule在JUnit中测试文件和目录

junit rule多亏了TemporaryFolder Rule在JUnit中使用文件和目录进行测试很容易。 在JUnit中&#xff0c;规则&#xff08; Rule &#xff09;可以用作夹具设置和清除方法&#xff08; org.junit.Before &#xff0c; org.junit.After &#xff0c; org.junit.BeforeClass和org…

oracle 递归计算,SQL(Oracle)中的递归计算

好吧,我想我已经有了解决方案.这些数字与你的数字有点不同,但我相当确定我的正在做你想要的.我们可以在第1步和第1步中完成所有工作. 2使用单个查询(main_sql).必须使用递归语句(recur_sql)完成3和4.with main_sql as (select a.*,b.*,sum(a_amt) over (partition by b_id) as …

C语言实现数据字节序交换的四种方式

1关于数据字节序的说明1&#xff09;关于字节序的说明字节序有两种大端和小端。大端&#xff1a;数据高位存放在低地址&#xff0c;地位放在高地址。如0x12345678在内存中存放为地址从左到右为低到高12345678。 小端&#xff1a;数据地位存放在低地址&#xff0c;高位存放在高地…

python 抓取微博评论破亿_一篇文章教会你使用Python定时抓取微博评论

【Part1——理论篇】试想一个问题&#xff0c;如果我们要抓取某个微博大V微博的评论数据&#xff0c;应该怎么实现呢&#xff1f;最简单的做法就是找到微博评论数据接口&#xff0c;然后通过改变参数来获取最新数据并保存。首先从微博api寻找 抓取评论的接口&#xff0c;如下图…

cassandra 入门_Apache Cassandra和Java入门(第一部分)

cassandra 入门在此页面上&#xff0c;您将学到足够的知识以开始使用NoSQL Apache Cassandra和Java&#xff0c;包括如何安装&#xff0c;尝试一些基本命令以及下一步要做什么。 要求 要遵循本教程&#xff0c;您应该已经有一个正在运行的Cassandra实例&#xff0c;并且已经在…