作者:微信小助手
发布时间:2022-07-29T10:01:43
BigDecimal
而导致故障的文章,但是除非在一些非常简单的场景,结算汇金类的业务也不会直接用
BigDecimal
来计算金额,原因有两点:
BigDecimal
里面还是有很多隐蔽的坑的
BigDecimal
没有提供金额的单位
1.
BigDecimal
中的五个容易踩的坑1.1
new BigDecimal()
还是BigDecimal#valueOf()
?
BigDecimal bd2 = BigDecimal.valueOf(0.01);
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);
bd2 = 0.01
BigDecimal
的时候就已经丢精度了,而
BigDecimal#valueOf
的实现却完全不同
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
BigDecimal
对象,因此避免了精度问题。所以大家要尽量要使用字符串而不是浮点数去构造
BigDecimal
对象,如果实在不行,就使用
BigDecimal#valueOf()
方法吧。
1.2 等值比较
BigDecimal bd2 = new BigDecimal("1.00");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2));
0
BigDecimal
中
equals
方法的实现会比较两个数字的精度,而
compareTo
方法则只会比较数值的大小。
1.3
BigDecimal
并不代表无限精度
BigDecimal b = new BigDecimal("3.0");
a.divide(b) // results in the following exception.
JVM
我们不需要返回精确的结果就好了
BigDecimal b = new BigDecimal("3.0");
a.divide(b, 2, RoundingMode.HALF_UP)// 0.33
1.4
BigDecimal
转回String
要小心
String out = d.toString(); // Or perform any formatting that needs to be done
System.out.println(out); // 1.23345353454567E+16
BigDecimal
有三个方法可以转为相应的字符串类型,切记不要用错:
String toPlainString(); // 不使用科学计数法
String toEngineeringString(); // 工程计算中经常使用的记录数字的方法,与科学计数法类似,但要求10的幂必须是3的倍数
1.5 执行顺序不能调换(乘法交换律失效)
BigDecimal b = BigDecimal.valueOf(3.0);
BigDecimal c = BigDecimal.valueOf(3.0);
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP).multiply(c)); // 0.990
System.out.println(a.multiply(c).divide(b, 2, RoundingMode.HALF_UP)); // 1.00
2. 最佳实践
BigDecimal
再封装一个
Money
类,其实我们直接可以用一个半官方的
Money
类:JSR 354 ,虽然没能在
Java 9
中成为
Java
标准,很有可能集成到后续的
Java
版本中成为官方库。
2.1
maven
坐标
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.1</version>
</dependency>
2.2 新建
Money
类
Money money = Money.of(1.0, cny);
// 或者 Money money = Money.of(1.0, "CNY");
//System.out.println(money);
2.3 金额运算
Money oneYuan = Money.of(1.0, cny);
Money threeYuan = oneYuan.add(Money.of(2.0, "CNY")); //CNY 3
Money tenYuan = oneYuan.multiply(10); // CNY 10
Money fiveFen = oneYuan.divide(2); //CNY 0.5
2.4 比较相等
Money anotherFiveFen = Money.of(0.50, "CNY"); // CNY 0.50
System.out.println(fiveFen.equals(anotherFiveFen)); // true
BigDecimal
的一些坑。