交易中的金额,如果以元为单位的话,不可避免的会涉及到小数,例如62.4元。但是因为double无法精确的表示某些小数,如0.4这种的。所以如果单纯使用double作为金额的类型,不可避免会有精度的损失。为了解决这个问题,常常有两种解决方案, 使用BigDecimal和将钱转为分为单位
BigDecimal
java.math提供的BigDecimal可以表示任意大小且精度完全准确的浮点数,但是在使用中有些场景需要特别注意
1.创建
创建应该使用new BigDecimal(string) 或者BigDecimal.valueOf(double), 避免使用new BigDecimal(double) ,但是有时这个问题并不一定会暴露出来,例如new BigDecimal(0.5)
2.比较
BigDecimal的比较使用==肯定是错的,因为对于对象,==比较的是引用
那么改用equals是否可以呢?答案也是否定的,因为equals除了比较值之外还会比较精度
正确的做法是使用compareTo,然后将结果和0比较
3.Denial of Service(DOS)漏洞
当对BigDecimal进行加减乘除时,如果传入的参数未经严格限定,会产生DoS,例如如下代码, 会导致CPU彪高,持续了90215ms
String price = "2e111111111";
BigDecimal t = new BigDecimal(price);
t = t.add(new BigDecimal("0.1"));
CPU使用情况
将单位转成分
因为金额的最小单位是分,所以把0.4元转成40分,然后使用int或者long来表示
服务端内部都是使用int或者long来交互,显示时转成String传递给前端,如"0.4"
结论
BigDecimal使用起来比较复杂,且很容易误用,推荐使用将单位转为分的方式
网友评论