BigDecimal详解

文章目录

  • 前言
  • 一、BigDecimal类
  • 二、常用方法
    • 1.构造方法
    • 2.基本的运算
      • 加法
      • 减法
      • 乘法
      • 除法
    • 3.保留小数(精确到几位)
    • 4.舍入的类型
        • ROUND_UP向上舍入
        • ROUND_DOWN向下舍入
        • ROUND_CEILING正向舍入
        • ROUND_FLOOR负向舍入
        • ROUND_HALF_UP四舍五入
        • ROUND_HALF_DOWN五舍六入
  • 总结


前言

最近项目中有个需求,需要将库中某个字段的值累加,并精确到小数点后两位,返回前端显示,开始使用的是Double去实现,没想到出了问题,Double数据类型在进行累加操作的时候会丢失精度,所以数据显示的时候,输出的是一个小数点后很长的数据,因此果断改为BigDeciml操作,刚好记录一下BigDemical的一些常用操作。


一、BigDecimal类

根据Java8中文手册,Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

二、常用方法

1.构造方法

  • BigDecimal(int) 创建一个具有参数所指定整数值的对象。
  • BigDecimal(double) 创建一个具有参数所指定双精度值的对象。(不建议采用)
  • BigDecimal(long) 创建一个具有参数所指定长整数值的对象。
  • BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象

构造方法一共有四种,其中使用double声明一个BigDecimal类时,尽量不要直接传入Double的值,因为这样构造的BigDemical是不可预知的,建议使用String.valueOf(number)传入

2.基本的运算

加法

使用add方法如下:

BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.add(new BigDecimal(456)))

如果被加的数是一个Double类型的数据建议使用以下写法:

BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.add(new BigDecimal(String.valueOf(0.45))))

先将数据转化为字符串,然后将使用构造方法
如果执行加法以后还要对结果进行舍入,那么可以做以下处理:

BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.add(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))

减法

使用subtract方法

BigDecimal num1 = new BigDecimal(456);
log.info("结果为:{}",num1.subtract(new BigDecimal(123)))

Double类型同上
同样也可以进行舍入

BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.subtract(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))

乘法

使用multiply方法

BigDecimal num1 = new BigDecimal(456);
log.info("结果为:{}",num1.multiply(new BigDecimal(123)))

Double类型同加法
同样也可以进行舍入

BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.multiply(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))

除法

使用divide方法

BigDecimal num1 = new BigDecimal(456);
log.info("结果为:{}",num1.divide(new BigDecimal(123)))

同样也可以进行舍入

BigDecimal num1 = new BigDecimal(123);
log.info("结果为:{}",num1.divide(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))

3.保留小数(精确到几位)

可以使用divide方法对一个BigDecimal类型的数据进行保留几位小数的处理
例如:

BigDecimal divisor = new BigDecimal(1000);
BigDecimal num = new BigDecimal(4561.2564);
num.divide(divisor, 2, BigDecimal.ROUND_CEILING)
log.info("原来的数除以1000保留两位小数:{}",num1.divide(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))

或者只保留两位小数

BigDecimal num = new BigDecimal(4561.2564);
num.setScale(2, BigDecimal.ROUND_CEILING)
log.info("原来的数除以1000保留两位小数:{}",num1.divide(new BigDecimal(String.valueOf(0.45),BigDecimal.ROUND_CEILING)))

4.舍入的类型

这里只记录可能会用到的几种类型

ROUND_UP向上舍入

无论正负,只要大于都会进一

 BigDecimal num = new BigDecimal(String.valueOf(1.4));
 System.out.println(num.setScale(0, BigDecimal.ROUND_UP));
 //2
 BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
 System.out.println(num1.setScale(0, BigDecimal.ROUND_UP));
 //-2

ROUND_DOWN向下舍入

无论正负,都会舍去

BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_DOWN));
//1
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_DOWN));
//-1

ROUND_CEILING正向舍入

是 ROUND_UP 和ROUND_DOWN 的组合,如果 BigDecimal 为正数,则行为与 ROUND_UP 相同;如果 BigDecimal 为负数,则行为与 ROUND_DOWN 相同

BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_CEILING));
//2
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_CEILING));
//-1

ROUND_FLOOR负向舍入

ROUND_UP 和 ROUND_DOWN 的组合,但是和ROUND_CEILING 是相反的。如果 BigDecimal 为正数,则行为与 ROUND_DOWN 相同;如果为负数,则行为与 ROUND_UP 相同

BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_FLOOR));
//1
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_FLOOR));
//-2

ROUND_HALF_UP四舍五入

这个就是我们经常使用的,不再解释

BigDecimal num = new BigDecimal(String.valueOf(1.4));
System.out.println(num.setScale(0, BigDecimal.ROUND_HALF_UP));
//1
BigDecimal num1 = new BigDecimal(String.valueOf(-1.4));
System.out.println(num1.setScale(0, BigDecimal.ROUND_HALF_UP));
//-1
BigDecimal num2 = new BigDecimal(String.valueOf(1.5));
System.out.println(num2.setScale(0, BigDecimal.ROUND_HALF_UP));
//2
BigDecimal num3 = new BigDecimal(String.valueOf(-1.5));
System.out.println(num3.setScale(0, BigDecimal.ROUND_HALF_UP));
//-2

ROUND_HALF_DOWN五舍六入

大于6就进一,小于6就舍去

BigDecimal num = new BigDecimal(String.valueOf(1.6));
System.out.println(num.setScale(0, BigDecimal.ROUND_HALF_DOWN));
//2
BigDecimal num1 = new BigDecimal(String.valueOf(-1.6));
System.out.println(num1.setScale(0, BigDecimal.ROUND_HALF_DOWN));
//-2
BigDecimal num2 = new BigDecimal(String.valueOf(1.5));
System.out.println(num2.setScale(0, BigDecimal.ROUND_HALF_DOWN));
//1
BigDecimal num3 = new BigDecimal(String.valueOf(-1.5));
System.out.println(num3.setScale(0, BigDecimal.ROUND_HALF_DOWN));
//-1

总结

BigDecimal在业务需求比较精准的情况下,是非常必要的,可以避免基本数据类型产生的bug

你可能感兴趣的:(业务场景,java,BigDecimal)