使用BigDecimal处理货币

我试图用自己的货币来创build我自己的货币类,但显然我应该使用BigDecimal 。 有人能帮我开始吗? 对于美元货币,使用BigDecimal的最好方法是什么?例如,至less使得美分的小数点后两位,等等BigDecimal的API是巨大的,我不知道使用哪种方法。 此外, BigDecimal有更好的精度,但是如果它通过一个double ? 如果我做新的BigDecimal(24.99) ,它将如何不同于使用double ? 或者我应该使用构造函数,而不是使用String

这里有一些提示:

  1. 使用BigDecimal进行计算,如果您需要它提供的精度(Money值通常需要这个)。
  2. 使用NumberFormat类来显示。 这门课将照顾不同货币金额的本地化问题。 但是,它只会采取原始的; 因此,如果您可以接受由于转换为double精度而导致的精度变化很小,您可以使用这个类。
  3. 使用NumberFormat类时,请使用BigDecimal实例上的scale()方法来设置精度和舍入方法。

PS:如果你想知道, BigDecimal总是比double ,当你必须在Java中代表金钱价值 。

PPS:

创buildBigDecimal实例

这很简单,因为BigDecimal提供了构造函数来获取原始值和String对象。 你可以使用这些, 最好是采用String对象的那个 。 例如,

 BigDecimal modelVal = new BigDecimal("24.455"); BigDecimal displayVal = modelVal.setScale(2, RoundingMode.HALF_EVEN); 

显示BigDecimal实例

您可以使用setMinimumFractionDigitssetMaximumFractionDigits方法调用来限制显示的数据量。

 NumberFormat usdCostFormat = NumberFormat.getCurrencyInstance(Locale.US); usdCostFormat.setMinimumFractionDigits( 1 ); usdCostFormat.setMaximumFractionDigits( 2 ); System.out.println( usdCostFormat.format(displayVal.doubleValue()) ); 

我会推荐一些有关Money Pattern的研究。 Martin Fowler在他的“分析模式”一书中详细介绍了这一点。

 public class Money { private static final Currency USD = Currency.getInstance("USD"); private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_EVEN; private BigDecimal amount; private Currency currency; public static Money dollars(BigDecimal amount) { return new Money(amount, USD); } Money(BigDecimal amount, Currency currency) { this(amount, currency, DEFAULT_ROUNDING); } Money(BigDecimal amount, Currency currency, RoundingMode rounding) { this.amount = amount; this.currency = currency; this.amount = amount.setScale(currency.getDefaultFractionDigits(), rounding); } public BigDecimal getAmount() { return amount; } public Currency getCurrency() { return currency; } @Override public String toString() { return getCurrency().getSymbol() + " " + getAmount(); } public String toString(Locale locale) { return getCurrency().getSymbol(locale) + " " + getAmount(); } } 

使用方法:

您将使用Money对象而不是BigDecimal来表示所有款项。 将货币表示为十进制小数将意味着您将在每次显示货币的地方格式化货币。 试想如果显示标准改变了。 你将不得不在整个地方进行编辑。 而是使用Money模式,将Money格式集中到一个位置。

 Money price = Money.dollars(38.28); System.out.println(price); 

或者,等待JSR-354 。 Java Money和货币API即将推出!

1)如果仅限于double精度,则使用BigDecimal的一个原因是通过double精度型来创buildBigDecimal

2) BigDecimal由一个任意精度的整数非标度值和一个非负32位整数标度组成,而double则包含一个对象中doubletypes的基本types的值。 Doubletypes的对象包含一个types为double的单个字段

3)应该没有区别

你应该没有困难与$和精度。 一种方法是使用System.out.printf

原始数字types可用于在存储器中存储单个值。 但是,在使用双精度和浮点types进行计算时,四舍五入会出现问题,这是因为内存表示不能完全映射到值。 例如,double值应该占用64位,但Java不会使用全部64位。它只存储它认为是数字的重要部分。 所以,当你将float和doubletypes的值相加时,你可能会得到错误的值。

请看https://youtu.be/EXxUSz9x7BM

当您想要将美分的两位小数四舍五入时BigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP)请使用BigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP) 。 当你做计算的时候要注意四舍五入的错误。 你需要一致的时候,你会做的钱的四舍五入。 在完成所有计算之后,在最后舍入权利,或者在进行任何计算之前对每个值应用舍入。 使用哪一个取决于您的业务需求,但总的来说,我认为最后做出正确的调整似乎对我更有意义。

当您构build货币价值的BigDecimal时使用一个String 。 如果使用double ,则在最后会有一个尾随浮点值。 这是由于计算机体系结构如何以二进制格式表示double / float值。

在javapractices.com上有一个广泛的例子。 特别参见Money类,这是为了使货币计算比直接使用BigDecimal更简单。

这个Money类的devise是为了使expression更自然。 例如:

 if ( amount.lt(hundred) ) { cost = amount.times(price); } 

WEB4J工具有一个类似Decimal类,它比Money类更精美一些。

 NumberFormat.getNumberInstance(java.util.Locale.US).format(num);