BigDecimal介绍和使用

前言

​ 在工作中,我们在针对金额类字段进行计算的时候,通常使用BigDecimal 类型的字段,来保留金额的精度。因此,本篇文章主要分享一下Java语言中的BigDecimal类的使用,以及使用过程中的坑。

1、概述

​ 在日常的开发工作中,针对有数据精度要求的金额数据,都会使用BigDecimal类型(不排除有些公司使用String类型处理)。BigDecimal是Java在java.math包中提供的线程安全的API类,可以用于表示任意精度数字的类,它可以表示无限长度的小数,BigDecimal 通常支持任意位数的小数部分,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。

2、常用API方法

构造方法
  • BigDecimal(String val) 创建一个具有参数所指定以字符串表示的数值的对象。 推荐使用
  • BigDecimal(int val) 创建一个具有参数所指定整数值的对象
  • BigDecimal(long val) 创建一个具有参数所指定长整数值的对象
  • BigDecimal(double val) 创建一个具有参数所指定双精度值的对象。不推荐使用,因为存在精度丢失问题
运算方法
  • add(BigDecimal) BigDecimal对象中的值相加
  • subtract(BigDecimal) BigDecimal对象中的值相减
  • multiply(BigDecimal) BigDecimal对象中的值相乘
  • divide(BigDecimal) BigDecimal对象中的值相除
  • abs() 将BigDecimal对象中的值转换成绝对值
  • doubleValue() 将BigDecimal对象中的值转换成双精度数
  • floatValue() 将BigDecimal对象中的值转换成单精度数
  • longValue() 将BigDecimal对象中的值转换成长整数
  • intValue() 将BigDecimal对象中的值转换成整数
  • compareTo(BigDecimal val) 比较大小,返回int类型。0(相等) 1(大于) -1(小于)
  • max(BigDecimal val) 两值比较,返回最大值
  • negate() 求相反数,正变负,负变正
  • pow(int n) 求乘方,如BigDecimal.valueOf(2).pow(3)的值为8
  • toPlainString() 不使用任何指数

以上就是BigDecimal的主要API方法和功能介绍

3、数据转换

3.1、BigDecimal的八种舍入模式

BigDecimal.setScale()方法用于格式化小数点

舍入模式 作用
setScale(1,BigDecimal.ROUND_DOWN) 直接删除多余的小数位 eg: 3.35会变成3.3
setScale(1,BigDecimal.ROUND_UP) 进位处理 eg: 3.35变成4.4
setScale(1,BigDecimal.ROUND_HALF_UP) 四舍五入 eg: 3.35变成3.4
setScaler(1,BigDecimal.ROUND_HALF_DOWN) 四舍五入 , 3.35变成3.3,如果是5以下则向下舍
setScaler(1,BigDecimal.ROUND_CEILING) 接近正无穷大的舍入
setScaler(1,BigDecimal.ROUND_FLOOR) 接近负无穷大的舍入,数字>0和ROUND_UP作用一样,数字<0和ROUND_DOWN作用一样
setScaler(1,BigDecimal.ROUND_HALF_EVEN) 向最接近的数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入
3.2 BigDecimal格式化、小数点转换
    public static void main(String[] s){

        //默认使用的是进位方式是RoundingMode.HALF_EVEN,此舍入模式也称为“银行家算法”,主要在美国使用
        DecimalFormat df = new DecimalFormat("###,##0.00");
        System.out.println(df.format(new BigDecimal("12333.435")));
        System.out.println(df.format(new BigDecimal(0)));
        System.out.println(df.format(new BigDecimal("0.04")));
        System.out.println(df.format(new BigDecimal("0.04444")));
        System.out.println(df.format(new BigDecimal("0.206")));
        System.out.println(df.format(new BigDecimal("1.22")));
    }
3.3、货币格式化与百分比格式化

NumberFormat对象:
getCompactNumberInstance();返回FORMAT带有"SHORT"格式样式的默认语言环境 的紧凑数字格式 。
getCurrencyInstance(Locale inLocale);返回指定语言环境的货币格式。若是不指定参数,则以默认语言为参数。
getInstance(Locale inLocale);返回指定语言环境的通用数字格式。若是不指定参数,则以默认语言为参数。
getPercentInstance(Locale inLocale);返回指定语言环境的百分比格式。若是不指定参数,则以默认语言为参数。

    public static void main(String[] s){
        NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用
        NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
        percent.setMinimumFractionDigits(2);//设置数的小数部分所允许的最小位数(如果不足后面补0)
        percent.setMaximumFractionDigits(3);//设置数的小数部分所允许的最大位数(如果超过会四舍五入)

        BigDecimal amount = new BigDecimal("3333.42"); //金额
        BigDecimal interestRate = new BigDecimal("1.0004"); //利率
        BigDecimal interest = amount.multiply(interestRate); //相乘
        System.out.println("金额: " + currency.format(amount));
        System.out.println("利率: " + percent.format(interestRate));
        System.out.println("利息: " + currency.format(interest));
    }

4、BigDecimal常见问题

4.1 等值比较

等值比较重 BigDecimal 中提供了 compareTo 方法,在很多时候需要使用compareTo 比较两个值。使用equals方法,值是比较不出来的。

4.2 使用BigDecimal进行计算时参数不能为NULL
4.3 创建 BigDecimal精度丢失的坑

看下面代码

    public static void main(String[] s){
        BigDecimal b1= new BigDecimal(0.1113);
        System.out.println(b1);
        BigDecimal b2= BigDecimal.valueOf(0.13);  //底层也是将值转成String 进行数据类型转换
        System.out.println(b2);
        BigDecimal b3= new  BigDecimal("0.1111112323111111111111111111111234");
        System.out.println(b3);
        BigDecimal b4= BigDecimal.valueOf(0.1111112323111111111111111111111234);
        System.out.println(b4);
    }

运行结果

0.11129999999999999615862833479695837013423442840576171875
0.13
0.1111112323111111111111111111111234
0.11111123231111111

因此 在使用BigDecimal构造函数时,尽量传递字符串而非浮点类型;

5、总结

我们日常使用的API要知其然还要知其所以然,了解其原理和坑,在开发中,我们才能使用的得心应手,避免出现问题。以上就是本次分享的所有内容,如有不足,请多多指教。

你可能感兴趣的:(Java基础,java)