如果你做过交易系统或者做过金额计算的,应该非常清楚float和double类型是尤其不适合用于货币上的计算。因为要让float和double精确到0.1是不可能的。
例如,你的账户里有1.13,花了0.82,那么结果是怎么样的呢?有些同学肯定会说,这还不简单,答案是0.31。请看下面的代码段。
System.out.println(1.13-0.82);
遗憾的告诉你,它打印出来的结果是0.30999999999999994,如下所示。
0.30999999999999994
有些同学会认为,做一下处理不就好了,四舍五入简单粗暴,但是注意这种做法并不适合有些场景。假设你账户里有1元,依次分别买了0.10元的A产品,0.20元的B产品,0.30元的C产品一直到1元(注意你是从标价为0.10的A产品开始买,直到你的余额支付不起下一个产品的价格),那么你能购买多少种呢?看下面的一段简单程序。
double money=1.00;
int products=0;
for (double price=0.10;money>=price;price+=0.10){
money-=price;
products++;
}
System.out.println("购买的产品:"+products+",还剩余额为:"+money);
结果为
购买的产品:3,还剩余额为:0.3999999999999999
当我们把double换成BigDecimal会出现什么情况呢?
BigDecimal money=new BigDecimal("1.00");
BigDecimal cents=new BigDecimal("0.10");
int products=0;
for (BigDecimal price=cents;money.compareTo(price)>=0;price=price.add(cents)){
money=money.subtract(price);
products++;
}
System.out.println("购买的产品:"+products+",还剩余额为:"+money);
结果为
购买的产品:4,还剩余额为:0.00
当我们修改程序后,这个才是我们想要的结果。然而使用BigDecimal有个缺点那就是速度慢。但是对于解决这个问题,牺牲点效率不算什么。除了用BigDecimal,int和long都可以进行货币的计算。到底选int和long取决于数值的大小。总而言之,如果你想要一个精准的数值,请不要使用float和double。虽然使用BigDecimal比基本类型使用相对不方便,但是使用过BigDecimal类型的同学应该知道,它可以控制舍入,在这方面,是非常方便的。如果你考虑性能上的因素,你可以使用int或者long(注意:不超过9位十进制数字用int)。