BigDecimal的个人总结

本文深入探讨了BigDecimal在Java中的使用场景及技巧,包括初始化注意事项、基本运算、常见问题解决方法及格式化技巧。

前言:
互联网公司,对于BigDecimal的使用,还是较为频繁的,那么就会涉及到关于这个类型的种种问题.

1:为什么使用BigDecimal
首先java八大基本类型真的很基本,4个整型搞不了小数,double和float搞的了小数,但搞不好,关键时刻就调链子,当然这也和他们存储方式有关(二进制无法精确的表示1/10),天生注定搞不了精密计算,尤其是和钱相关的.

所以一般我们对于精密点的计算和涉及货币的计算,都会使用BigDecimal.他的出现,就是为了解决基本数据类型浮点数不能进行精确计算的问题.

2:如何使用BigDecimal
就说最常用的:
2.1.初始化,一般使用这个构造方法:new BigDecimal(String value);
其他的不再多说,某度很多,只能说我们一般都会用这个String类型的入参

关于BigDecimal的初始化,有一个坑要注意,就是尽量使用String类型的去初始化。
不信的话,可以看看下面的例子:
		BigDecimal a = new BigDecimal(1.01);
        BigDecimal b = new BigDecimal(1.02);
        BigDecimal c = new BigDecimal("1.01");
        BigDecimal d = new BigDecimal("1.02");
        System.out.println(a.add(b));
        System.out.println(c.add(d));
最终的打印结果是:
2.0300000000000000266453525910037569701671600341796875
2.03
很明显,也是精度问题。这块要注意。

2.2.基本运算

add(BigDecimal)            BigDecimal对象中的值相加,然后返回这个对象。
subtract(BigDecimal)       BigDecimal对象中的值相减,然后返回这个对象。
multiply(BigDecimal)       BigDecimal对象中的值相乘,然后返回这个对象。
divide(BigDecimal)         BigDecimal对象中的值相除,然后返回这个对象。
toString()                 将BigDecimal对象中的值以字符串形式返回。
doubleValue()              将BigDecimal对象中的值以双精度数返回。
floatValue()               将BigDecimal对象中的值以单精度数返回。
longValue()                将BigDecimal对象中的值以长整数返回。
intValue()                 将BigDecimal对象中的值以整数返回。

3.采坑经验(敲黑板的重点!!!)
3.1.将BigDecimal类性的值(10.1000)传给页面后,页面展示的(10.1000)不是我们想要的(10.1),该怎么处理?

    BigDecimal money;
   
    public BigDecimal getMoney() {
        return money;
    }
    
    最开始上面的这种处理方式,如果money是10.1000,那么get方法也会拿到10.1000,
    但其实我们想要的是10.1就好了.
-------------------------------------------------------------------------    
    那怎么办,直接上最终版(重写个getMoneyString方法):
    public String getMoneyString() {
        return money.stripTrailingZeros().toPlainString();
    }
    这个方法返回的,就是10.1,String类型的
--------------------------------------------------------------------------
	解释下:
	1.stripTrailingZeros()方法
		官方文档对返回的解释是:
		a numerically equal BigDecimal with any trailing zeros removed.
		而且从方法名就可以看出来,就是去掉末尾的0.
		那么,为什么还要用toPlainString()方法呢?
		看个例子:
		new BigDecimal("60000.000").stripTrailingZeros();
		这个结果是6E+4,而不是我们想要的60000,而且官方文档上也说明了,返回的值,会用科学计数法来表示,所以看下个方法
	
    2.toPlainString()
	    官方文档对返回的解释是:
		a string representation of this BigDecimal without an exponent field.
		就是返回一个不用指数表示的字符串形式的值.
	
	所以两个方法连用,就可以达到对BigDecimal的初步控制.
		

3.2.值的比较用compareTo,不要用equals
compareTo:左边比右边数大,返回1,相等返回0,比右边小返回-1
equals:BigDecimal重写了equals,比较的是数值

3.3.除法要养成习惯去设置精度,以免出现无限循环的小数而抛异常
(java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result)

new BigDecimal("10").divide(new BigDecimal("3"));
这个就会抛出上面的异常.所以要用下面的

new BigDecimal("10").divide(new BigDecimal("3"), 4,        BigDecimal.ROUND_HALF_DOWN);
这个代表10除以3,结果保留4位小数,采用四舍五入保留
所以结果就是:3.3333

3.4.既然用了BigDecimal了,就应避免再与浮点类型互相转换,否则精度会受很大的影响

4.BigDecimal格式化
可以使用NumberFormat类的format(BigDecimal)方法,利用NumberFormat不同类型的实例,对BigDecimal转换不同的格式.详细可以查查NumberFormat的各种实例方法,比如:
NumberFormat.getCurrencyInstance();
NumberFormat.getCurrencyInstance();
NumberFormat.getInstance();

根据不同的需求,使用不同的格式…
下面提供两个现成的转换精度的方法

/**
     *
     * @param obj 传入的BigDecimal类型
     * @return 返回String类型,保留两位小数(四舍五入),不够补0
     */
    public static String formatToStringWithTwoPlaces(BigDecimal obj) {
        DecimalFormat df = new DecimalFormat("#.00");
        if (obj.compareTo(BigDecimal.ZERO) == 0) {
            return "0.00";
        } else if (obj.compareTo(BigDecimal.ZERO) > 0 && obj.compareTo(new BigDecimal(1)) < 0) {
            return "0" + df.format(obj).toString();
        } else {
            return df.format(obj).toString();
        }
    }
    //这个方法效果和上一个一样,两种不同的实现罢了
    public static String getDecimalStr(BigDecimal bd) {
        String bdStr;
        if (bd != null) {
            bdStr = bd.setScale(2, RoundingMode.HALF_EVEN).toPlainString();
        } else {
            bdStr = "0.00";
        }
        return bdStr;
    }
    
    public static void main(String[] args) {
    	//各种类型测试
        BigDecimal bigDecimal1 = new BigDecimal("0");
        System.out.println(formatToStringWithTwoPlaces(bigDecimal1));//0.00
        BigDecimal bigDecimal11 = new BigDecimal("0.6");
        System.out.println(formatToStringWithTwoPlaces(bigDecimal11));//0.60
        BigDecimal bigDecimal12 = new BigDecimal("0.6666");
        System.out.println(formatToStringWithTwoPlaces(bigDecimal12));//0.67
        BigDecimal bigDecimal2 = new BigDecimal("2");
        System.out.println(formatToStringWithTwoPlaces(bigDecimal2));//2.00
        BigDecimal bigDecimal3 = new BigDecimal("2.1");
        System.out.println(formatToStringWithTwoPlaces(bigDecimal3));//2.10
        BigDecimal bigDecimal4 = new BigDecimal("2.22");
        System.out.println(formatToStringWithTwoPlaces(bigDecimal4));//2.22
        BigDecimal bigDecimal5 = new BigDecimal("2.333");
        System.out.println(formatToStringWithTwoPlaces(bigDecimal5));//2.33

        BigDecimal bigDecimal15 = new BigDecimal("0");
        System.out.println(getDecimalStr(bigDecimal15));//0.00
        BigDecimal bigDecimal115 = new BigDecimal("0.6");
        System.out.println(getDecimalStr(bigDecimal115));//0.60
        BigDecimal bigDecimal125 = new BigDecimal("0.6666");
        System.out.println(ConvertUtil.getDecimalStr(bigDecimal125));//0.67
        BigDecimal bigDecimal25 = new BigDecimal("2");
        System.out.println(getDecimalStr(bigDecimal25));//2.00
        BigDecimal bigDecimal35 = new BigDecimal("2.1");
        System.out.println(getDecimalStr(bigDecimal35));//2.10
        BigDecimal bigDecimal45 = new BigDecimal("2.22");
        System.out.println(getDecimalStr(bigDecimal45));//2.22
        BigDecimal bigDecimal55 = new BigDecimal("2.333");
        System.out.println(getDecimalStr(bigDecimal55));//2.33
    }
    

5.BigDecimal取整

    public static void main(String[] args) {
        BigDecimal bigDecimal = new BigDecimal(6.66);
        
        //6.66除以6,向上取整,结果为2
        BigDecimal divide = bigDecimal.divide(BigDecimal.valueOf(6),0, BigDecimal.ROUND_UP);
        System.out.println(divide);//2

        //6.66除以6,不报错,但有这么多小数跟在后面
        BigDecimal divide2 = bigDecimal.divide(BigDecimal.valueOf(6), BigDecimal.ROUND_UP);
        System.out.println(divide2);//1.110000000000000023684757858670006195704142252605

        //1.110000000000000023684757858670006195704142252605向上取整,结果为2
        BigDecimal bigDecimal1 = divide2.setScale(0, BigDecimal.ROUND_UP);
        System.out.println(bigDecimal1);

        //6.66除以6,报错:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
        BigDecimal divide1 = bigDecimal.divide(BigDecimal.valueOf(6));
        System.out.println(divide1);//报错
    }

各个roundingMode详解如下:
ROUND_UP:非0时,舍弃小数后(整数部分)加1,比如1.11结果为2,-1.11结果为 -2
ROUND_DOWN:直接舍弃小数
ROUND_CEILING:如果 BigDecimal 是正的,则做 ROUND_UP 操作;如果为负,则做 ROUND_DOWN 操作 (一句话:取附近较大的整数)
ROUND_FLOOR: 如果 BigDecimal 是正的,则做 ROUND_DOWN 操作;如果为负,则做 ROUND_UP 操作(一句话:取附近较小的整数)
ROUND_HALF_UP:四舍五入(取更近的整数)
ROUND_HALF_DOWN:跟ROUND_HALF_UP 差别仅在于0.5时会向下取整
ROUND_HALF_EVEN:取最近的偶数
ROUND_UNNECESSARY:不需要取整,如果存在小数位,就抛ArithmeticException 异常

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值