• java中的BigDecimal使用


    1、什么是BigDecimal

    BigDecimal属于java.math包,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。

    float和double只能用来做科学计算或者是工程计算,在商业计算中(如金融行业)要用java.math.BigDecimal。

    BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

    2、为什么使用BigDecimal?

    我们看如下代码:

    public static void main(String[] args) throws Exception {
            System.out.println(0.2 + 0.1);
            System.out.println(0.3 - 0.1);
            System.out.println(0.2 * 0.1);
            System.out.println(0.3 / 0.1);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    打印结果:

    在这里插入图片描述
    为何会这样?

    原因:不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度。

    根本原因:十进制值通常没有完全相同的二进制表示形式;十进制数的二进制表示形式可能不精确。只能无限接近于那个值。

    但是,在项目中,我们不可能让这种情况出现,特别是金融项目,因为涉及金额的计算都必须十分精确,否则,如果你的微信账户余额显示193.99999999999998,那是一种怎么样的体验?

    3、如何使用BigDecimal?

    (1)BigDecimal初始化赋值

    方法类型描述
    public BigDecimal(int val)构造函数int类型的值生成BigDecimal对象
    public BigDecimal(long val)构造函数long类型的值生成BigDecimal对象
    public BigDecimal(String val)静态方法String类型的值转换为BigDecimal类型
    public static BigDecimal valueOf(double val)静态方法double类型的值转换为BigDecimal类型
    public static BigDecimal valueOf(long val)静态方法long类型(包含int类型)的值转换为BigDecimal类型

    代码示例:

     		BigDecimal b = new BigDecimal("25");
            BigDecimal c = new BigDecimal(12);
    
            System.out.println(b);
            System.out.println(c);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    打印结果:

    在这里插入图片描述

    注意:不建议使用public BigDecimal(double val)方式初始化值

    如下代码:

    		BigDecimal c = new BigDecimal(12.3);
            System.out.println(c);
    
    • 1
    • 2

    打印结果:

    在这里插入图片描述
    如图,也会出现计算的错误。

    通常建议优先使用String构造方法。当double必须用作BigDecimal的源时,请使用Double.toString(double)转成String,然后使用String构造方法,或使用BigDecimal的静态方法valueOf:

    		BigDecimal b = new BigDecimal("12.3");
            BigDecimal c = BigDecimal.valueOf(7.34325);
            BigDecimal d = new BigDecimal(Double.toString(7.34325));
            System.out.println(b);
            System.out.println(c);
            System.out.println(d);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    打印结果:

    在这里插入图片描述

    (2)加减乘除运算

    运算法则对应方法
    加法public BigDecimal add(BigDecimal value)
    减法public BigDecimal subtract(BigDecimal value)
    乘法public BigDecimal multiply(BigDecimal value)
    除法public BigDecimal divide(BigDecimal value)

    代码示例:

    public static void main(String[] args) throws Exception {
            System.out.println("计算加法: " + BigDecimal.valueOf(1.9).add(BigDecimal.valueOf(0.2)));
            System.out.println("计算减法: " + BigDecimal.valueOf(1.9).subtract(BigDecimal.valueOf(1.5)));
            System.out.println("计算乘法: " + BigDecimal.valueOf(1.9).multiply(BigDecimal.valueOf(0.2)));
            System.out.println("计算除法: " + BigDecimal.valueOf(1.9).divide(BigDecimal.valueOf(0.2)));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    打印结果:

    在这里插入图片描述
    注意点:

    1. BigDecimal的运算结果都是返回了一个新的BigDecimal对象,并不是在原有的对象上进行操作。

    代码示例:

    public static void main(String[] args)  {
            BigDecimal bigDecimal = new BigDecimal("2");
            System.out.println("bigDecimal计算前的地址是:"+System.identityHashCode(bigDecimal));
            bigDecimal = bigDecimal.add(BigDecimal.valueOf(3));
            System.out.println("bigDecimal计算后的地址是:"+System.identityHashCode(bigDecimal));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    打印结果:
    在这里插入图片描述

    1. 使用divide除法函数除不尽,出现无线循环小数的时候,就需要使用另外精确的小数位数以及舍入模式,不然会出现报错。

    代码示例:

    public static void main(String[] args)  {
            BigDecimal a = BigDecimal.valueOf(10), b = BigDecimal.valueOf(3);
            System.out.println(a.divide(b));
        }
    
    • 1
    • 2
    • 3
    • 4

    报错如下:

    在这里插入图片描述

    解决方法可以采用四舍五入的方式,详情见下文!

    (3)BigDecimal保留两位小数及舍入模式

    public BigDecimal setScale(int newScale, int roundingMode)
    
    • 1

    用于格式化小数的方法,第一个值表示保留几位小数,第二个值表示格式化的类型。
    8种类型如下:

    格式化类型描述
    ROUND_DOWN舍弃多余位数,如1.55会格式化为1.5,-1.55会格式化为-1.5
    ROUND_UP进位处理,如1.52会格式化为1.6,-1.52会格式化为-1.6
    ROUND_HALF_UP四舍五入,如果舍弃部分>= .5,则进位
    ROUND_HALF_DOWN五舍六入,如果舍弃部分> .5,则进位
    ROUND_CEILING正无穷大方向舍入模式。如果值为正数,则与ROUND_UP模式相同;如果值为负数,则与ROUND_DOWN模式相同
    ROUND_FLOOR负无穷大方向舍入模式。如果值为正数,则与ROUND_DOWN模式相同;如果值为负数,则与ROUND_UP模式相同
    ROUND_UNNECESSARY确认值的小数位数是否与传入第一个参数(保留小数的位数)相等,如果符合则返回值,如果不符抛出异常
    ROUND_HALF_EVEN如果舍弃部门左边的数字为奇数,则与ROUND_HALF_UP模式相同,如果为偶数则与ROUND_HALF_DOWN模式相同

    代码示例:

    public static void main(String[] args)  {
            BigDecimal a = BigDecimal.valueOf(5.445);
            System.out.println("5.445舍弃多余位数:" + a.setScale(2, BigDecimal.ROUND_DOWN));
            System.out.println("5.445进位处理:" + a.setScale(2, BigDecimal.ROUND_UP));
            System.out.println("5.445四舍五入(舍弃部分>= .5,进位):" + a.setScale(2, BigDecimal.ROUND_HALF_UP));
            System.out.println("5.445四舍五入(舍弃部分未> .5,舍弃):" + a.setScale(2, BigDecimal.ROUND_HALF_DOWN));
            System.out.println("5.446四舍五入(舍弃部分> .5,进位):" + BigDecimal.valueOf(5.446).setScale(2, BigDecimal.ROUND_HALF_DOWN));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    打印结果:
    在这里插入图片描述

    (4)BigDecimal比较大小

    public int compareTo(BigDecimal val)
    
    • 1

    BigDecimal类提供的比较值的方法,注意比较的两个值均不能为空。
    a.compareTo(b)得到结果 1, 0, -1。

    比较结果描述
    1a 大于b
    0a 等于b
    -1a 小于b

    代码示例:

    public static void main(String[] args)  {
            BigDecimal a = BigDecimal.valueOf(1);
            BigDecimal b = BigDecimal.valueOf(2);
            BigDecimal c = BigDecimal.valueOf(1);
            BigDecimal d = BigDecimal.ZERO;
            System.out.println("1和2比较结果:" + a.compareTo(b));
            System.out.println("1和1比较结果:" + a.compareTo(c));
            System.out.println("1和0比较判断:" + (a.compareTo(d) > 0) );
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    打印结果:
    在这里插入图片描述

    注意:实际业务中,不会单纯的比较谁打谁小,而是类似于第三条去判断一个布尔值。

    (5)BigDecimal其他方法及常量

    代码类型描述
    BigDecimal.ZERO常量初始化一个为0的BigDecimal对象
    BigDecimal.ONE常量初始化一个为1的BigDecimal对象
    BigDecimal.TEN常量初始化一个为10的BigDecimal对象
    public BigDecimal abs()方法求绝对值,不管正数还是负数,都得到正数
    public BigDecimal negate()方法求相反数,正变负,负变正
    public BigDecimal pow(int n)方法求乘方,如BigDecimal.valueOf(2).pow(3)的值为8
    public BigDecimal max(BigDecimal val)方法两值比较,返回最大值
    public BigDecimal min(BigDecimal val)方法两值比较,返回最小值
  • 相关阅读:
    微服务项目实战-黑马头条(十三):持续集成
    搞懂了Vue对象与实例的区别!
    2023.9.2 关于 JVM 垃圾回收机制(GC)
    线上出问题了,怎么办?
    SaaS 电商设计 (二) 全链路解决方案概述和核心业务流程梳理
    网易数帆陈谔:低代码平台,应对企业应用开发复杂性的一剂良方
    无锡地铁4号线一期工程天河停车场项目中智能照明监控系统的应用
    Jetson Xavier NX 与笔记本网线连接 ,网络共享,ssh连接到vscode
    PMP考试是什么?适合哪些人学?
    上午面了个腾讯拿 38K 出来的,让我见识到了基础的天花板
  • 原文地址:https://blog.csdn.net/m0_58680865/article/details/127938819