zoukankan      html  css  js  c++  java
  • Java BigDecimal使用指南

    提起BigDecimal,相信大家都使用过,之所以总结这篇呢,是因为最近发现项目中使用的不是太规范,在某些场景下甚至出现代码抛出异常的情况,

    所以就总结了这篇,希望大家在使用时,可以少踩一些坑。

    1. 基本运算

    1.1 加法

    BigDecimal number1 = new BigDecimal("88.88");
    BigDecimal number2 = new BigDecimal("11.12");
    
    BigDecimal number3 = number1.add(number2);
    System.out.println("number1 add number2 = " + number3);
    

    输出结果:

    number1 add number2 = 100.00

    1.2 减法

    BigDecimal number1 = new BigDecimal("88.88");
    BigDecimal number2 = new BigDecimal("11.12");
    
    BigDecimal number3 = number1.subtract(number2);
    System.out.println("number1 subtract number2 = " + number3);
    

    输出结果:

    number1 subtract number2 = 77.76

    1.3 乘法

    BigDecimal number1 = new BigDecimal("88.88");
    BigDecimal number2 = new BigDecimal("11.12");
    
    BigDecimal number3 = number1.multiply(number2);
    System.out.println("number1 multiply number2 = " + number3);
    

    输出结果:

    number1 multiply number2 = 988.3456

    1.4 除法

    BigDecimal number1 = new BigDecimal("88");
    BigDecimal number2 = new BigDecimal("11");
    
    BigDecimal number3 = number1.divide(number2);
    System.out.println("number1 divide number2 = " + number3);
    

    输出结果:

    number1 divide number2 = 8

    因为上面2个数可以整除,所以这么用没有问题,不过一但不能被整除,这么用就会有潜在的风险,会抛出java.lang.ArithmeticException异常,所以强烈建议像下面这样使用

    BigDecimal number1 = new BigDecimal("88.88");
    BigDecimal number2 = new BigDecimal("11.12");
    
    BigDecimal number3 = number1.divide(number2, 2, RoundingMode.HALF_UP);
    System.out.println("number1 divide number2 = " + number3);
    

    输出结果:

    number1 divide number2 = 7.99

    此时使用的divide()方法源码如下所示:

    public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {
        return divide(divisor, scale, roundingMode.oldMode);
    }
    

    这里的scale指的是要保留的小数位数,我们传的是2,即保留2位小数。

    这里的roundingMode指的是舍入模式,我们这里传的是RoundingMode.HALF_UP,即经常使用的四舍五入模式。

    1.5 保留小数位数

    如果我们想对BigDecimal类型保留小数位数,可以使用setScale()方法,使用方法如下所示:

    BigDecimal number1 = new BigDecimal("88.88");
    BigDecimal number2 = new BigDecimal("11.12");
    
    BigDecimal number3 = number1.multiply(number2);
    System.out.println("number1 multiply number2 = " + number3);
    
    // 保留3位小数,四舍五入
    BigDecimal number4 = number3.setScale(3, RoundingMode.HALF_UP);
    System.out.println("number3 setScale = " + number4);
    

    输出结果:

    number1 multiply number2 = 988.3456

    number3 setScale = 988.346

    1.6 比较大小

    BigDecimal比较大小,可以使用compareTo()方法,使用方法如下所示:

    BigDecimal number1 = new BigDecimal("88.88");
    BigDecimal number2 = new BigDecimal("11.11");
    BigDecimal number3 = new BigDecimal("99.99");
    BigDecimal number4 = new BigDecimal("88.88");
    
    System.out.println("number1 compareTo number2 = " + number1.compareTo(number2));
    System.out.println("number1 compareTo number3 = " + number1.compareTo(number3));
    System.out.println("number1 compareTo number4 = " + number1.compareTo(number4));
    

    输出结果:

    number1 compareTo number2 = 1

    number1 compareTo number3 = -1

    number1 compareTo number4 = 0

    由输出结果可以看出:

    当number1小于number2时,返回-1,

    当number1等于number2时,返回0,

    当number1大于number2时,返回1。

    2. 踩坑总结

    2.1 NullPointerException异常

    在使用BigDecimal类型进行计算时,比如上面提到的加、减、乘、除、比较大小时,一定要保证参与计算的两个值不能为空,否则会抛出java.lang.NullPointerException异常。

    比如下面的2段代码,都会抛出异常:

    BigDecimal number1 = null;
    BigDecimal number2 = new BigDecimal("11.12");
    
    BigDecimal number3 = number1.add(number2);
    System.out.println("number1 add number2 = " + number3);
    
    BigDecimal number1 = new BigDecimal("88.88");
    BigDecimal number2 = null;
    
    BigDecimal number3 = number1.add(number2);
    System.out.println("number1 add number2 = " + number3);
    

    抛出的异常如下图所示:

    2.2 ArithmeticException异常

    一次在使用BigDecimaldivide方法时,抛出java.lang.ArithmeticException异常,错误代码如下所示:

    // 含税金额
    BigDecimal inclusiveTaxAmount = new BigDecimal("1000");
    // 税率
    BigDecimal taxRate = new BigDecimal("0.13");
    // 不含税金额 = 含税金额 / (1+税率)
    BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate));
    
    System.out.println(exclusiveTaxAmount);
    

    运行时抛出以下异常:

    java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

    报错原因是因为无法整除,导致结果是无限循环小数:

    解决方案是指定下舍入模式,比如我们最常用的四舍五入模式:

    // 不含税金额 = 含税金额 / (1+税率)
    BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate),RoundingMode.HALF_UP);
    

    此时不再报错,输出结果为:

    885

    但这里我的需求是保留2位小数,四舍五入,因此代码应该是下面这样的:

    // 不含税金额 = 含税金额 / (1+税率)
    BigDecimal exclusiveTaxAmount = inclusiveTaxAmount.divide(BigDecimal.ONE.add(taxRate), 2, RoundingMode.HALF_UP);
    

    此时的输出结果为:

    884.96

    如果你的IDEA装了阿里巴巴代码规范插件,如果不指定RoundingMode,会有下面这样的提示:

    3. 使用规范

    尽量不要在项目中使用new BigDecimal("0"),而是使用BigDecimal提供的常量BigDecimal.ZERO

    BigDecimal zero = BigDecimal.ZERO;
    BigDecimal one = BigDecimal.ONE;
    BigDecimal ten = BigDecimal.TEN;
    

  • 相关阅读:
    Java的运算符
    Java的输入和输出
    ieda使用maven出现unable to find valid certification path to requested target问题解决
    linux设置mysql查询忽略表明大小写的配置
    idea插件GsonFormat的使用
    Charles抓包(iOS的http/https请求)
    (转)Java线上应用故障排查之一:高CPU占用
    基本功知识点
    MYSQL 什么时候用单列索引?什么使用用联合索引?(收集)
    Quartz定时器中的misfire指定解析
  • 原文地址:https://www.cnblogs.com/zwwhnly/p/13575828.html
Copyright © 2011-2022 走看看