用于Java应用程序的最佳数据类型是什么?在Java应用程序中用于金钱的最佳数据类型是什么?
回答
Java有Currency
类,它表示的ISO 4217货币代码。 BigDecimal
是表示货币小数值的最佳类型。
Joda Money提供了一个库来代表金钱。
为什么我们不能用float或double来代替? –
@Borat Sagdiyev [这就是为什么](http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems)。另外,你可以参考[this](https://www.securecoding.cert.org/confluence/display/java/NUM04-J.+Do+not+use+floating-point+numbers+if+precise+computation + +是必需的)。 –
@Borat:如果您知道自己在做什么,请参阅Peter Lawrey的[本文](http://vanillajava.blogspot.com/2011/08/double-your-money-again.html)。但使用BigDecimals看起来至少要做所有的四舍五入的麻烦。 –
我会用Joda Money
它仍然在0.6的版本,但看起来非常有前途
BigDecimal要使用货币的最佳数据类型。
货币有很多容器,但它们都使用BigDecimal作为基础数据类型。 BigDecimal不会出错,可能使用BigDecimal.ROUND_HALF_EVEN四舍五入。
您应该使用的BigDecimal代表货币价值。它使您可以使用各种舍入模式,并在 金融应用,舍入模式往往是一个硬性要求 可能甚至受到法律的规定。
表示可能的最小值的整数类型。换句话说,你的程序应该以美分来计算,而不是以美元/欧元计算。
这不应该阻止你把gui翻译回美元/欧元。
请记住,金额可能会溢出int – eversor
@eversor的大小,这将需要超过2000万美元大多数应用程序不需要那么多,如果他们做了很长时间就足够了,因为即使我们的govenrments处理足够的货币溢出, –
@ratchetfreak可能更好地使用一个很长的时间。 –
BigDecimal可以用,为什么不使用浮点数或双精度可以在这里看到很好的解释:Why not use Double or Float to represent currency?
我喜欢使用Tiny Types,它会包含double,BigDecimal或int,如前面的答案所建议的。 (除非出现精度问题,否则我会使用双精度值)。
一个微小的类型给你类型安全,所以你不会把双重钱与其他双打混淆。
虽然我也喜欢微小的类型,但您绝对不应该使用double来存储货币值。 – orien
您可以使用货币和货币API(JSR 354)。此API预计将成为Java 9的一部分。如果您为项目添加适当的依赖关系,则可以在Java 7和Java 8中使用此API。
对于Java 8,作为一个依赖添加下面的参考实现您的pom.xml
:
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.0</version>
</dependency>
这种依赖性将增加及物动词为javax.money:money-api
依赖。
然后,您可以使用API:
package com.example.money;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;
import java.util.Locale;
import javax.money.Monetary;
import javax.money.MonetaryAmount;
import javax.money.MonetaryRounding;
import javax.money.format.MonetaryAmountFormat;
import javax.money.format.MonetaryFormats;
import org.junit.Test;
public class MoneyTest {
@Test
public void testMoneyApi() {
MonetaryAmount eurAmount1 = Monetary.getDefaultAmountFactory().setNumber(1.1111).setCurrency("EUR").create();
MonetaryAmount eurAmount2 = Monetary.getDefaultAmountFactory().setNumber(1.1141).setCurrency("EUR").create();
MonetaryAmount eurAmount3 = eurAmount1.add(eurAmount2);
assertThat(eurAmount3.toString(), is("EUR 2.2252"));
MonetaryRounding defaultRounding = Monetary.getDefaultRounding();
MonetaryAmount eurAmount4 = eurAmount3.with(defaultRounding);
assertThat(eurAmount4.toString(), is("EUR 2.23"));
MonetaryAmountFormat germanFormat = MonetaryFormats.getAmountFormat(Locale.GERMAN);
assertThat(germanFormat.format(eurAmount4), is("EUR 2,23"));
}
}
我已经做了微基准(江铃控股)比较莫尼塔(Java JSR货币执行354)针对BigDecimal的在性能方面。
令人惊讶的是,BigDecimal的表现似乎比moneta更好。 我已经使用以下莫尼塔配置:
org.javamoney.moneta.Money.defaults.precision = 19 org.javamoney.moneta.Money.defaults.roundingMode = HALF_UP
package com.despegar.bookedia.money;
import org.javamoney.moneta.FastMoney;
import org.javamoney.moneta.Money;
import org.openjdk.jmh.annotations.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.concurrent.TimeUnit;
@Measurement(batchSize = 5000, iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@Warmup(iterations = 2)
@Threads(value = 1)
@Fork(value = 1)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
public class BigDecimalBenchmark {
private static final Money MONEY_BASE = Money.of(1234567.3444, "EUR");
private static final Money MONEY_SUBSTRACT = Money.of(232323, "EUR");
private static final FastMoney FAST_MONEY_SUBSTRACT = FastMoney.of(232323, "EUR");
private static final FastMoney FAST_MONEY_BASE = FastMoney.of(1234567.3444, "EUR");
MathContext mc = new MathContext(10, RoundingMode.HALF_UP);
@Benchmark
public void bigdecimal_string() {
new BigDecimal("1234567.3444").subtract(new BigDecimal("232323")).multiply(new BigDecimal("3.4"), mc).divide(new BigDecimal("5.456"), mc);
}
@Benchmark
public void bigdecimal_valueOf() {
BigDecimal.valueOf(12345673444L, 4).subtract(BigDecimal.valueOf(232323L)).multiply(BigDecimal.valueOf(34, 1), mc).divide(BigDecimal.valueOf(5456, 3), mc);
}
@Benchmark
public void fastmoney() {
FastMoney.of(1234567.3444, "EUR").subtract(FastMoney.of(232323, "EUR")).multiply(3.4).divide(5.456);
}
@Benchmark
public void money() {
Money.of(1234567.3444, "EUR").subtract(Money.of(232323, "EUR")).multiply(3.4).divide(5.456);
}
@Benchmark
public void money_static(){
MONEY_BASE.subtract(MONEY_SUBSTRACT).multiply(3.4).divide(5.456);
}
@Benchmark
public void fastmoney_static() {
FAST_MONEY_BASE.subtract(FAST_MONEY_SUBSTRACT).multiply(3.4).divide(5.456);
}
}
从而造成
钱:Benchmark Mode Cnt Score Error Units
BigDecimalBenchmark.bigdecimal_string thrpt 10 479.465 ± 26.821 ops/s
BigDecimalBenchmark.bigdecimal_valueOf thrpt 10 1066.754 ± 40.997 ops/s
BigDecimalBenchmark.fastmoney thrpt 10 83.917 ± 4.612 ops/s
BigDecimalBenchmark.fastmoney_static thrpt 10 504.676 ± 21.642 ops/s
BigDecimalBenchmark.money thrpt 10 59.897 ± 3.061 ops/s
BigDecimalBenchmark.money_static thrpt 10 184.767 ± 7.017 ops/s
,如果我失去了一些东西
有趣的是,我将在JDK9上运行与最新内容相同的测试 – kensai
JSR 354,请随时指正和Currency API
JSR 354提供了一个用于使用货币和货币表示,运输和执行综合计算的API。你可以从这个链接下载:
JSR 354: Money and Currency API Download
该规范由以下几件事:
- 处理E中的API。 G。货币量和货币
- API来支持互换实现
- 工厂创建的实现类的实例
- 功能为货币金额计算,转换和格式化
- 的Java API与金钱和货币,这是工作计划包含在Java 9中。
- 所有规范类和接口都位于javax.money。*包中。
JSR 354的样品例子:金钱和货币API:
创建一个MonetaryAmount并打印到控制台的一个例子是这样的::
MonetaryAmountFactory<?> amountFactory = Monetary.getDefaultAmountFactory();
MonetaryAmount monetaryAmount = amountFactory.setCurrency(Monetary.getCurrency("EUR")).setNumber(12345.67).create();
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
当使用参考实施API,必要的代码要简单得多:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
API还支持与MonetaryAmounts计算:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmount otherMonetaryAmount = monetaryAmount.divide(2).add(Money.of(5, "EUR"));
CurrencyUnit和MONETARYAMOUNT
// getting CurrencyUnits by locale
CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN);
CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);
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可以使用舍入运算符四舍五入:
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
使用MonetaryAmounts的集合时,可以使用一些很好的实用工具筛选,排序和分组方法。
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"));
定制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
资源:
Handling money and currencies in Java with JSR 354
所有这一切都很好,但是正如Federico上面所建议的那样,它看起来比BigDecimal慢:-))只是坏的笑话,但我现在会在1年后给它测试。 .. – kensai
对于简单情况(一种货币),这已经足够了Integer
/Long
。 以美分(......)或百分之一/分(以固定分隔线所需的任何精度)保留金额
- 1. Xamarin.Forms中用于存储应用程序数据的最佳Environment.SpecialFolder是什么?
- 2. 收集关于应用程序使用数据的最佳方法是什么?
- 3. 用于小型Java桌面应用程序的最佳嵌入式数据库是什么?
- 4. 用于ChatRoom应用程序的最佳UI控件是什么?
- 5. 什么是访问数据库的最佳基于Web的应用程序
- 6. 设置java应用程序的最佳方式是什么?
- 7. 什么是最佳的Java Web应用程序托管?
- 8. 分发Java应用程序的最佳方式是什么?
- 9. 在应用程序中加密数据的最佳方式是什么
- 10. 在ios中存储应用程序数据的最佳地点是什么?
- 11. 在Android中存储应用程序数据的最佳方式是什么?
- 12. 对于java应用程序,在处理金钱时使用BigDecimal是否安全,还是应该使用整数并为金钱创建抽象?
- 13. 如何金钱的数量型Java中
- 14. 什么是审计大型java/j2ee web应用程序的最佳方法
- 15. Facebook的应用程序ID是什么数据类型?
- 16. 用于在Java中读取文件的最佳/最简单的类是什么?
- 17. 什么是ASP.net应用程序的最佳性能计数器?
- 18. 在Java中编写命令行应用程序的最佳方式是什么?
- 19. 什么是皮肤我的iPhone应用程序的最佳方式(类似于皮肤的Notes应用程序)?
- 20. 复合应用程序中域模型重用的最佳做法是什么?
- 21. 金融应用程序中必需的货币数据类型?
- 22. 什么是覆盖mvc应用程序中数据验证的最佳方法
- 23. 什么是MySQL中货币的最佳数据类型?
- 24. Android应用程序中用于传递JSON数据的RESTful API的最佳线程选择是什么?
- 25. 使用应用程序预加载数据的最佳方式是什么?
- 26. 什么是Django中行级权限的最佳应用程序?
- 27. 什么是Java Key:用于重复值的值数据类型?
- 28. 在asp.net应用程序中存储SMTP凭据的最佳做法是什么?
- 29. Django Admin应用程序的最佳用途是什么?
- 30. 什么是与java程序一起使用的最佳数据库?
这取决于您要执行的操作。请提供更多信息。 – eversor
@eversor你能否介绍一下哪些数据类型应该用于不同的操作? – questborn
我正在做计算,这需要我准确地代表美分。 – questborn