使用BigDecimal需要避免的坑

使用BigDecimal需要避免的坑

1.直接用浮点数初始化
2 加减乘除时不设精度
3 用 equals 判断相等
4 使用 scale 时忽视实际含义
5 忽略不可变性
6 忽视性能问题

package com.example.core.mydemo.java3;

import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * link: https://www.cnblogs.com/oktokeep/p/18350065
 * BigDecimal加减乘除运算,保留2位小数点,初始化,与0的比较
 */
public class BigDecimalTest {
    public static void main(String[] args) {
        //1.直接用浮点数初始化
        BigDecimal num = new BigDecimal(0.1);
        System.out.println(num);   //0.1000000000000000055511151231257827021181583404541015625

        //注意:永远不要用 BigDecimal(double) 构造函数,用字符串或整数更靠谱。也可以使用BigDecimal.valueOf()函数。
        BigDecimal num2 = new BigDecimal("0.1");
        System.out.println(num2);  //0.1

        //2 加减乘除时不设精度
        BigDecimal a = new BigDecimal("1.03");
        BigDecimal b = new BigDecimal("0.42");
        //减法
        BigDecimal result = a.subtract(b);
        System.out.println(result);   //0.61

        BigDecimal c = new BigDecimal("10");
        BigDecimal d = new BigDecimal("3");
//        BigDecimal result2 = c.divide(d);
//        System.out.println(result2);  //报错了  Non-terminating decimal expansion; no exact representable decimal result.
        //报错的根本原因:10/3 是无限小数,BigDecimal 默认不保留小数点后面,精度溢出。
        //注意: 在BigDecimal 做除法时 ,必须指定精度。
        BigDecimal result3 = c.divide(d, 2, RoundingMode.HALF_UP);
        System.out.println(result3);

        //3 用 equals 判断相等
        BigDecimal x = new BigDecimal("1.0");
        BigDecimal y = new BigDecimal("1.00");

        System.out.println(x.equals(y));  //false   尽管 1.0 和 1.00 的数值相等,但精度不一样,equals 判定为不同。
        //优化方法,用 compareTo 比较数值:
        System.out.println(x.compareTo(y) == 0);

        //4 使用 scale 时忽视实际含义
        BigDecimal num3 = new BigDecimal("123.45000");
        System.out.println(num3.scale());  //5

        BigDecimal stripped = num3.stripTrailingZeros();
        System.out.println(stripped.scale());  //2
        //明确 scale 的含义。  我们不要混淆 scale(刻度) 和 precision(精度),必要时显式设置小数位数。
        BigDecimal fixed = num3.setScale(2, RoundingMode.HALF_UP);
        System.out.println(fixed);

        //5 忽略不可变性
        BigDecimal sum = new BigDecimal("0");
        for (int i = 0; i < 5; i++) {
            sum.add(new BigDecimal("1"));
        }
//        问题原因是 add 方法不会改变原对象,而是返回一个新的 BigDecimal 实例.
        System.out.println(sum);  //0
        //用变量接住返回值。
        BigDecimal sum2 = new BigDecimal("0");
        for (int i = 0; i < 5; i++) {
            sum2 = sum2.add(new BigDecimal("1"));
        }
        //BigDecimal 操作后需要接住新实例。
        System.out.println(sum2);  //5

        //6 忽视性能问题
        BigDecimal principal = new BigDecimal("10000");
        BigDecimal rate = new BigDecimal("0.05");
        BigDecimal interest = principal.multiply(rate);
        System.out.println(interest);  //500.00
        //能用整数就用整数(比如分代替元)。
        //批量计算时,用 double 计算,结果最后转换成 BigDecimal。
        //参与大批量计算时,两个BigDecimal对象直接计算会比较慢,尽量少用,能优化的地方别放过。
        double principal2 = 10000;
        double rate2 = 0.05;
        BigDecimal interest2 = BigDecimal.valueOf(principal2 * rate2);
        System.out.println(interest2);

    }
}

 

posted on 2025-03-03 18:27  oktokeep  阅读(137)  评论(0)    收藏  举报