Java应用程序中用于赚钱的最佳数据类型是什么?
答案 0 :(得分:115)
Java有Currency
类,代表ISO 4217货币代码。
BigDecimal
是表示货币十进制值的最佳类型。
Joda Money提供了一个代表金钱的图书馆。
答案 1 :(得分:32)
您可以使用货币和货币API(JSR 354)。只要向项目添加适当的依赖项,就可以使用此API。
对于Java 8,将以下参考实现添加为cublas
:
pom.xml
此依赖项将传递性地添加<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.0</version>
</dependency>
作为依赖项。
然后您可以使用API:
javax.money:money-api
答案 2 :(得分:21)
表示可能的最小值的整数类型。换句话说,你的程序应该用美分/欧元来思考。
这不应该阻止你将gui翻译成美元/欧元。
答案 3 :(得分:10)
BigDecimal,可以在此处看到有关不使用Float或Double的原因的详细说明:Why not use Double or Float to represent currency?
答案 4 :(得分:8)
JSR 354:货币和货币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
答案 5 :(得分:6)
我会使用Joda Money
它仍处于0.6版本,但看起来很有希望
答案 6 :(得分:5)
我已经做了一个微基准测试(JMH)来比较Moneta(java货币JSR 354实现)与BigDecimal的性能。
令人惊讶的是,BigDecimal的表现似乎比moneta更好。 我使用了以下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
如果我遗失了某些内容,请随时纠正我
答案 7 :(得分:4)
您应该使用 BigDecimal 来表示货币值。它允许您使用各种舍入模式,并且 在财务应用中,舍入模式通常是一项硬性要求 甚至可能是法律规定的。
答案 8 :(得分:4)
对于简单案例(一种货币),它足够Integer
/ Long
。
以美分(...)或百分之一/千分之一(固定分频器所需的任何精度)保持货币。
答案 9 :(得分:2)
BigDecimal是用于货币的最佳数据类型。
货币有很多容器,但它们都使用BigDecimal作为基础数据类型。 BigDecimal你可能不会出错,可能使用BigDecimal.ROUND_HALF_EVEN舍入。
答案 10 :(得分:2)
我喜欢使用Tiny Types来填充double,BigDecimal或int,就像先前的答案所建议的那样。 (除非出现精确问题,否则我会使用双倍。)
Tiny Type为您提供类型安全性,因此您不会将双倍金钱与其他双打混淆。