BigDecimal数据类型加减乘除之间的一些问题
了解BigDecimal类型
BigDecimal是java中一个用于表示任意精度的实数的类,它可以表示非常大或非常小的数,同时还能保持精确度。
与其他基本数据类型不同的是,BigDecimal提供了精确的计算,支持加,减,乘,除以及取余等运算。同时BigDecimal还可以设置精度和舍入模式,从而保证计算结果的准确性。
BigDecimal设置精度和舍入的方式
首先,可以使用setScale(int newScale, RoundingMode roundingMode)设置精度和舍入模式,newScale表示要设置的精度,roundingMode表示要使用的舍入模式。
BigDecimal decimal = new BigDecimal("3.14159"); BigDecimal result = decimal.setScale(2,RoundingMode.HALF_UP);
在这个例子中,设置了结果的精度为 2,使用的舍入模式为 RoundingMode.HALF_UP。表示采用“四舍五入”的方式进行舍入,保留两位小数.
在 Java 中,BigDecimal 类提供了多种舍入模式,用于指定进行四舍五入时的规则。以下是 RoundingMode 枚举类中定义的八种舍入模式:
UP:向远离零的方向舍入,即“正无穷”方向,例子:3.125 舍入为 3.13。DOWN:向靠近零的方向舍入,即“负无穷”方向,例子:-3.125 舍入为 -3.12。CEILING:向正无穷的方向舍入,如果为正数则执行UP舍入,如果为负数则执行DOWN舍入,例子:3.125 舍入为 3.13,-3.125 舍入为 -3.12。FLOOR:向负无穷的方向舍入,如果为正数则执行DOWN舍入,如果为负数则执行UP舍入,例子:3.125 舍入为 3.12,-3.125 舍入为 -3.13。HALF_UP:向最接近的整数方向舍入。如果两个相邻的整数中间有距离相等,则向上舍入。例如,2.5 舍入为 3.0,-2.5 舍入为 -3.0。HALF_DOWN:向最接近的整数方向舍入。如果两个相邻的整数中间有距离相等,则向下舍入。例如,2.5 舍入为 2.0,-2.5 舍入为 -2.0。HALF_EVEN:向最接近的整数方向舍入。如果两个相邻的整数中间有距离相等,则向相邻的偶数舍入。例如,2.5 舍入为 2.0,3.5 舍入为 4.0。UNNECESSARY:断言请求的操作具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定了此类舍入模式,则抛出ArithmeticException异常。
加法运算
public BigDecimal add(BigDecimal augend),其中 augend 是被加数,返回相加后的结果。
BigDecimal num1 = new BigDecimal("1.23"); BigDecimal num2 = new BigDecimal("2.34"); // 加法 BigDecimal sum = num1.add(num2); System.out.println("和:" + sum);
减法运算
public BigDecimal subtract(BigDecimal subtrahend),其中 subtrahend 是减数,返回相减后的结果。
// 减法 BigDecimal diff = num1.subtract(num2); System.out.println("差:" + diff);
乘法运算
public BigDecimal multiply(BigDecimal multiplicand),其中 multiplicand 是乘数,返回相乘后的结果。
// 乘法 BigDecimal product = num1.multiply(num2); System.out.println("积:" + product);
除法运算
public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode),其中 divisor 是除数,scale 是小数点后保留的位数,roundingMode 是舍入模式,返回相除后的结果。需要注意的是,divide() 方法在进行除法运算时,如果除不尽会抛出 ArithmeticException 异常。另外,在进行除法运算时,需要指定舍入模式,否则可能会出现精度问题。
// 除法 BigDecimal quotient = num1.divide(num2, 2, RoundingMode.HALF_UP); System.out.println("商:" + quotient);
在进行运算的时注意事项
构造器中传入字符串:BigDecimal 类的构造方法接受 String 类型的参数,而不是 double 或 float。因为 double 或 float 类型在转换成二进制时存在精度损失,这会导致最终结果不准确。
指定精度和舍入模式:在进行除法和四舍五入运算时,需要指定精确到小数点后几位以及舍入规则,否则会产生舍入误差。精度可以通过 scale 参数指定,舍入模式可以通过 RoundingMode 枚举类中的常量指定。
避免使用 equals() 方法比较大小:BigDecimal 类的 equals() 方法只能用于判断两个对象是否相等,不能直接用于比较大小。使用compareTo() 方法进行大小比较时,要考虑正负数、相等等多种情况。
不可变性:BigDecimal 对象是不可变的,一旦创建就不能修改它的值。每个运算都创建一个新的对象,所以不要用 == 运算符比较 BigDecimal 类型的对象。
适当缓存常用的 BigDecimal 对象:对于一些常用的小数或整数,可以将它们缓存起来,以避免重复创建 BigDecimal 对象,提升运算效率。
避免使用 floatValue() 和 doubleValue() 方法:这两个方法会将 BigDecimal 转换为 float 和 double 类型,存在精度损失。建议使用 toString() 方法或直接输出 BigDecimal 对象来查看结果
产生no value present异常时,一般是传入了空的BigDecimal对象,但一般的判断非空的方法就没什么用,比如
//报错 BigDecimal bigDecimal = list.stream().filter(fruitOrder -> (fruitOrder.getPayment() !=null)).map(FruitOrder::getPayment).reduce(BigDecimal::add).get(); //不报错 BigDecimal bigDecimal = list.stream().filter(fruitOrder -> Objects.nonNull(fruitOrder.getPayment())).map(FruitOrder::getPayment).reduce(BigDecimal::add).get();

可以使用Objects.nonNull() 进行非空判断。
浙公网安备 33010602011771号