一 BigDecimal 易错点
关于BigDecimal值 0.000000后缀会变成 0E-x ,x代表的是小数的位数,如8位小数 0E-8,9位小数 0E-9
用的是mysql5.7 数据库保存项为0.00000000,但java查出来后变成 0E-8
看到这里很多朋友会以为是mysql或查询框架有问题,下面再做测试:
执行结果:
不是mysql也不是查询框架的问题。要明白在BigDecimal用 toString() 超过6位会用指数的中文方式展示,要想保留非指数字符形式要用toPlainString().
二 BigDecimal 最常用法
在Java中,BigDecimal
是用于处理高精度计算的类,特别是在涉及财务计算时广泛使用。与浮点型数据类型(如 float
和 double
)相比,BigDecimal
可以避免由于精度损失导致的计算误差。以下是一些在应用开发中使用 BigDecimal
的经验和最佳实践:
1. 创建 BigDecimal
对象
-
使用
String
创建: 直接使用String
构造器创建BigDecimal
对象,避免浮点数不精确的问题。例如:BigDecimal bd1 = new BigDecimal("0.1"); // 推荐 BigDecimal bd2 = new BigDecimal(0.1); // 不推荐
使用
double
参数构造时,0.1
实际上是一个近似值,可能导致精度丢失。 -
使用
BigDecimal.valueOf(double)
方法: 这是另一种推荐的方式,内部会避免精度损失:BigDecimal bd = BigDecimal.valueOf(0.1);
2. 四则运算
BigDecimal
的加、减、乘、除运算不能直接使用运算符,需要调用相应的方法:
- 加法:
add(BigDecimal augend)
- 减法:
subtract(BigDecimal subtrahend)
- 乘法:
multiply(BigDecimal multiplicand)
- 除法:
divide(BigDecimal divisor, RoundingMode roundingMode)
(除法必须指定舍入模式)
例如:
BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("2.3");
BigDecimal result = a.add(b); // 加法
3. 除法时处理舍入
在除法操作中,可能会出现无法整除的情况,此时需要指定舍入方式,否则会抛出 ArithmeticException
。
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP); // 保留2位小数,四舍五入
4. 舍入模式 (RoundingMode
)
常见的舍入模式有:
RoundingMode.HALF_UP
:四舍五入RoundingMode.HALF_DOWN
:五舍六入RoundingMode.DOWN
:直接舍去小数部分RoundingMode.UP
:向远离零的方向舍入
根据业务需求选择合适的舍入模式尤为重要,特别是在财务应用中。
5. 精度设置
在进行货币计算时,需要控制结果的小数位数,并在除法、乘法等运算中指定精度。例如:
BigDecimal value = new BigDecimal("100.12345");
BigDecimal roundedValue = value.setScale(2, RoundingMode.HALF_UP); // 保留两位小数
6. 不可变性与链式操作
BigDecimal
是不可变的,每次进行算术操作时都会返回一个新的 BigDecimal
对象。这意味着在进行链式操作时需要小心,确保对每一步的结果进行处理:
BigDecimal result = a.add(b).subtract(c).multiply(d);
7. 避免使用 equals
比较大小
使用 equals
方法进行比较时,BigDecimal
会同时考虑值和精度(小数位数),这通常不是预期的效果。正确的做法是使用 compareTo
方法:
BigDecimal a = new BigDecimal("10.00");
BigDecimal b = new BigDecimal("10.0");
System.out.println(a.equals(b)); // false
System.out.println(a.compareTo(b)); // 0(表示两者相等)
compareTo
返回 -1
表示小于,0
表示等于,1
表示大于。
8. 结合 BigDecimal
和 MathContext
可以使用 MathContext
来统一控制计算时的精度和舍入模式,适用于更复杂的计算场景:
MathContext mc = new MathContext(4, RoundingMode.HALF_UP);
BigDecimal result = a.multiply(b, mc);
9. 性能考虑
BigDecimal
在高频运算中可能性能较低。对于不要求高精度的场景,可以考虑使用 double
或 BigDecimal.valueOf
等。
10. 常见的业务应用场景
- 货币计算: 在金融系统中,通过
BigDecimal
进行精确的货币运算,确保无精度损失。 - 税务计算: 需要在税率、折扣计算中使用
BigDecimal
以避免计算误差。
总结
BigDecimal
是处理高精度计算的核心类,正确的创建、运算、舍入和比较方法非常重要。对于需要确保精度的业务场景,合理使用 BigDecimal
能够有效避免计算错误。