BigDecimal的使用

1,090 阅读4分钟

BigDecimal可以理解为一个浮点数, 其大小可任意指定而且精度准确, 故日常用在金额,利息等金钱相关的字段上,因最近使用较多,故记录一下,给大家参考一下,避免其中的问题.

1 常见使用方式构造方法

// 使用字符串,不会出现精度损失 (推荐)
// 结果: 0.1
 BigDecimal bigDecimal = new BigDecimal("0.1"); 

// 使用int整数,会出现精度损失
// 结果: 0.1000000000000000055511151231257827021181583404541015625
 BigDecimal bigDecimal2 = new BigDecimal(0.1);

ps: String和BigDecimal互相转换

// 字符串转BigDecimal
String str = "100.01";
BigDecimal bigDecimal = new BigDecimal(str); 

// BigDecimal转字符串
BigDecimal big = new BigDecimal("13.14"); 
String string = big.toString();
String string2 = String.valueOf(big);

2 BigDecimal中scale使用

1 scale说明

scale是BigDecimal的一个成员属性,final关键字修饰,不能修改,表示小数位数.

        BigDecimal d1 = new BigDecimal("12.10");
        BigDecimal d2 = new BigDecimal("123.1000");
        BigDecimal d3 = new BigDecimal("1234500");
		// 小数位 2
        System.out.println(d1.scale()); 
		// 小数位 4
        System.out.println(d2.scale()); 
`		// 小数位 0 
        System.out.println(d3.scale()); 

2 stripTrailingZeros()方法使用

BigDecimal中stripTrailingZeros()方法,可以转换成一个新的BigDecimal,去掉了末尾的数字0.

        BigDecimal d1 = new BigDecimal("123.4500");
        BigDecimal d2 = d1.stripTrailingZeros();
		// 小数位 4
        System.out.println(d1.scale()); 
		// 小数位 2,因为去掉了00
        System.out.println(d2.scale()); 

        BigDecimal d3 = new BigDecimal("1234500");
        BigDecimal d4 = d3.stripTrailingZeros();
		// 小数位 0
        System.out.println(d3.scale()); 
		// 小数位 -2
        System.out.println(d4.scale()); 

总结:

1 一个 BigDecimal对象的scale()方法返回负数, 如-2,表示这个数是整数,结尾有2个0

2 一个BigDecimal对象结尾没有0,再调用stripTrailingZeros()方法,得到的结果不变.

3 精度转换

类型说明
ROUND_DOWN去掉多余的位数
ROUND_UP向前进位处理
ROUND_CEILING如果是正数,就是ROUND_UP ; 如果是负数,就是ROUND_DOWN
ROUND_FLOOR如果是正数,就是ROUND_DOWN ; 如果是负数,就是ROUND_UP
ROUND_HALF_UP四舍五入,大于等于5,就进位(>=5)
ROUND_HALF_DOWN四舍五入,大于5,才进位(>5)
ROUND_HALF_EVEN如果舍弃部分左边的数字为偶数,为HALF_DOWN ; 如果舍弃部分左边的数字为奇数,为ROUND_HALF_UP
ROUND_UNNECESSARY断言请求的操作具有精确的结果,因此不需要舍入
// 关于模式,旧的和新的描述不一样,但效果一致
        // 直接去掉多余的位数
        // 1  RoundingMode.DOWN == BigDecimal.ROUND_DOWN  
        BigDecimal b = new BigDecimal("2.225667").setScale(2, BigDecimal.ROUND_DOWN);
        System.out.println(b);

        // 跟上面相反,进位处理
        // 2  RoundingMode.UP == BigDecimal.ROUND_UP
        BigDecimal c = new BigDecimal("2.224667").setScale(2, BigDecimal.ROUND_UP);
        System.out.println(c);

        // 如果是正数,相当于BigDecimal.ROUND_UP ; 如果是负数,相当于BigDecimal.ROUND_DOWN
        // 3  RoundingMode.CEILING == BigDecimal.ROUND_CEILING
        BigDecimal f = new BigDecimal("2.224667").setScale(2, BigDecimal.ROUND_CEILING);
        System.out.println(f);
        BigDecimal g = new BigDecimal("-2.225667").setScale(2, BigDecimal.ROUND_CEILING);
        System.out.println(g);

        // 如果是正数,相当于BigDecimal.ROUND_DOWN ; 如果是负数,相当于BigDecimal.ROUND_HALF_UP
        // 4  RoundingMode.FLOOR == BigDecimal.ROUND_FLOOR
        BigDecimal h = new BigDecimal("2.225667").setScale(2, BigDecimal.ROUND_FLOOR);
        System.out.println(h);
        BigDecimal i = new BigDecimal("-2.224667").setScale(2, BigDecimal.ROUND_FLOOR);
        System.out.println(i);

        // 四舍五入(若舍弃部分>=.5,就进位)
        // 5  RoundingMode.HALF_UP == BigDecimal.ROUND_HALF_UP
        BigDecimal d = new BigDecimal("2.225").setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println("ROUND_HALF_UP" + d);

        // 四舍五入(若舍弃部分>.5,就进位)
        // 6  RoundingMode.HALF_DOWN == BigDecimal.ROUND_HALF_DOWN
        BigDecimal e = new BigDecimal("2.225").setScale(2, BigDecimal.ROUND_HALF_DOWN);
        System.out.println("ROUND_HALF_DOWN" + e);

        // 如果舍弃部分左边的数字为偶数,则作   ROUND_HALF_DOWN ; 如果舍弃部分左边的数字为奇数,则作   ROUND_HALF_UP
        // 7  RoundingMode.HALF_EVEN == BigDecimal.ROUND_HALF_EVEN
        BigDecimal j = new BigDecimal("2.225").setScale(2, BigDecimal.ROUND_HALF_EVEN);
        System.out.println(j);
        BigDecimal k = new BigDecimal("2.215").setScale(2, BigDecimal.ROUND_HALF_EVEN);
        System.out.println(k);


        // 断言请求的操作具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。
        // 8  RoundingMode.UNNECESSARY == BigDecimal.ROUND_UNNECESSARY
        BigDecimal bigDecimal = new BigDecimal("2.215").setScale(3, BigDecimal.ROUND_UNNECESSARY);
        System.out.println(bigDecimal);


3 BigDecimal的运算

1 加减乘除

计算加、减、乘,不会有精度丢失,除法运算时,如果存在无法除尽,需要指定精度.

        BigDecimal n = new BigDecimal("123.456");
        BigDecimal m = new BigDecimal("23.456789");

        // 加法
        System.out.println(n.add(m));
        // 减法
        System.out.println(n.subtract(m));
        // 乘法
        System.out.println(n.multiply(m));
        // 除法
        // 报错:ArithmeticException,因为除不尽
	   //  System.out.println(n.divide(m));
        // 保留10位小数并四舍五入
        System.out.println(n.divide(m, 10, RoundingMode.HALF_UP));

2 divideAndRemainder()方法

返回的数组包含两个BigDecimal,分别是商和余数,其中商总是整数,余数不会大于除数.

        BigDecimal n = new BigDecimal("12.75");
        BigDecimal m = new BigDecimal("0.15");
        BigDecimal[] dr = n.divideAndRemainder(m);
        if (dr[1].signum() == 0) {
            System.out.println("n是m的整数倍");
        }

        System.out.println(dr[0]);
        System.out.println(dr[1]);

3 compareTo()方法

比较两个BigDecimal, 不要使用==equals()方法==,因为==equals()方法==既要求两个BigDecimal值相等,还要求两个对象的小数位相等.

        BigDecimal d1 = new BigDecimal("123.1");
        BigDecimal d2 = new BigDecimal("123.10");
        
        // false,因为scale不同
        System.out.println(d1.equals(d2));
        // true,因为d2去除尾部0后scale变为2
        System.out.println(d1.equals(d2.stripTrailingZeros())); 

BigDecimal的比较, 需要使用==compareTo()方法==, 根据两个对象比较的结果返回负数,0和正数

        // 相等  0
        BigDecimal d1 = new BigDecimal("123.1");
        BigDecimal d2 = new BigDecimal("123.1");
        System.out.println(d1.compareTo(d2));

        // 大于  1
        BigDecimal d3 = new BigDecimal("123.2");
        BigDecimal d4 = new BigDecimal("123.1");
        System.out.println(d3.compareTo(d4));

        // 小于 -1
        System.out.println(d4.compareTo(d3));

在使用中,尽量靠近0去做判断比较, 听说可能会出现比较结果为小数的情况, 但是博主暂时没有发现.

注意:

​ 总是使用compareTo()比较两个BigDecimal的值,不要使用equals()