代码评审——BigDecimal的初始化问题

问题描述

在项目开发过程中,经常会使用到金额、百分比等数据的情况。在用代码实现的过程中,就会遇到BigDecimal的使用。下面我们将着重看下BigDecimal初始化时的问题。
金额、百分比等不使用FloatDouble的主要原因是精度问题。可以参考​effective java 第209页​。

float 和 double 类型主要是为了科学计算和工程计算而设计的,它们执行二进制浮点运算,这是为了在广泛的数值范围上提供较为精确的快速近似计算而精心设计的。
然而,它们并没有提供完全精确的结果,所以不应该被用于需要精确结果的场合 float double 类型尤其不适合用于货币计算 ,因为要让一个 float,double 精确地表示 0.1 (或者 的任何其他负数次方值 )是不可能的。

我们继续讨论BigDecimal的使用。用以下代码举例:

BigDecimal bd1 = new BigDecimal(1.00):

此时,使用静态代码扫描工具,会出现以下提示:
在这里插入图片描述


原因分析:

详细分析:

最主要的原因是由于BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。

首先,BigDecimal存在以下4中构造器:

  1. BigDecimal(int)
  2. BigDecimal(double) 【不推荐使用】
  3. BigDecimal(long)
  4. BigDecimal(String) 【推荐使用】

通过以下代码来测试,BigDecimal(double)存在精度的问题。

public static void main(String[] args) {
	BigDecimal bd1 = new BigDecimal("0.06");
	BigDecimal bd2 = new BigDecimal(0.06);
	System.out.println(bd1);
	System.out.println(bd2);
}

运行结果为:

0.06
0.059999999999999997779553950749686919152736663818359375

很明显已经不是我们想要的结果了。


解决方案:

根据上面的测试,可以使用以下两种方式来构造。

  1. 将double通过Double.toString(double)先转为String,然后放入BigDecimal的String构造函数中。
  2. 不通过BigDecimal的构造函数,而是通过它的静态方法BigDecimal.valueOf(double),也同样不会丢失精度。
public static void main(String[] args) {
	String string = Double.toString(0.06);
	BigDecimal stringBigDecimal = new BigDecimal(string);
	BigDecimal bigDecimal = BigDecimal.valueOf(0.06);
	System.out.println("stringBigDecimal = " + stringBigDecimal);
	System.out.println("bigDecimal = " + bigDecimal);
}

运行结果如下:

stringBigDecimal = 0.06
bigDecimal = 0.06

总结:

  • BigDecimal的初始化要使用String入参或者BigDecimal.valueOf();
  • 浮点数的格式化建议使用BigDecimal
  • 比较两个BigDecimal的value要使用compareTo()。
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值