众所周知,大多数编程语言中,在表达浮点数时都是不够精确的。java亦是如此。在一些金融或者电商项目中,往往涉及到一些金额,成交价,卖价以及一些数值方面的计算,对数值的精度要求比较高,通常我们会使用到BigDecimal来进行处理。
创建BigDecimal对象
和其他基础数据类型的包装类使用很类似,可通过BigDecimal.valueOf(val)或者构造函数来创建一个BigDecimal对象
BigDecimal bigDecimal1 = new BigDecimal(0.3);
BigDecimal bigDecimal2 = BigDecimal.valueOf(2L);
可以看到,BigDecimal类中,会将传入的数值赋值给成员变量stringCache,成员变量scale记录的是数值的标度(标度,类似与精度的概念)。
浮点数0.3,本身在计算机中就是以近似值表示的,封装成BigDecimal对象后仍然是不精确的近似值,因此,对于浮点数,强烈建议使用字符串的构造方法来创建对象!!!
常用操作
加减乘除操作很简单,所有人都会,这里就随便贴一下代码:
BigDecimal bigDecimal1 = new BigDecimal("0.3");
BigDecimal bigDecimal2 = new BigDecimal("0.2");
BigDecimal result1 = bigDecimal1.add(bigDecimal2);
BigDecimal result2 = bigDecimal1.subtract(bigDecimal2);
BigDecimal result3 = bigDecimal1.multiply(bigDecimal2);
// 除法必须设置保留小数位的策略,否则如果结果是无限循环小数,会抛出异常
BigDecimal result4 = bigDecimal1.divide(bigDecimal2,2,RoundingMode.HALF_UP);
除法这里必须要有保留小数位的策略,否则如果结果是无限循环小数,会抛出异常。
小数保留策略
通过setScale(int newScale, RoundingMode roundingMode)可以设置结果的小数位数
几种保留小数位的策略如下:
RoundingMode.UP :远离零方向舍入
RoundingMode.DOWN:向零方向舍入
RoundingMode.CEILING:向正无限大方向舍入
RoundingMode.FLOOR: 向负无限大方向舍入
RoundingMode.HALF_UP: 四舍五入,最常用
RoundingMode.HALF_DOWN: 向最接近的数字方向舍入,如果与两个相邻数字的距离相等,则向下舍入
RoundingMode.HALF_EVEN: 向最接近数字方向舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入
RoundingMode.UNNECESSARY: 用于断言请求的操作具有精确结果,因此不发生舍入
数值转字符串:
Bigdecmal提供了toString()以及toPlainString()方法,其中,toString可能会以科学记数法的方式返回字符串,而toPlainString是不使用科学技术法
BigDecimal bigDecimal1 = new BigDecimal("0.00000000999999");
String value1 = bigDecimal1.toString(); // 9.99999E-9
String value2 = bigDecimal1.toPlainString(); // 0.00000000999999
比较大小
Bigdecmal提供了compareTo()和equals()方法来进行数值大小的比较,两者的区别是equals除了比较数值外,还会比较标度。而compareTo方法仅比较数组是否相同
总结
1.由于计算机中浮点数会以近似值来表示,推荐使用BigDecimal来进行数值的运算和表示
2.创建BigDecimal对象时,如果是浮点数,需转换为字符串后进行创建
3.除法运算注意除数为0以及保留小数位的策略
4.比较大小时,注意数值标度,大多数业务场景会下都使用compareTo()方法来进行比较
5.web开发中,请求和响应实体类都可以使用String类型接受浮点数值,运算时转换为BigDecimal进行计算处理