好的,阿杰 😊
下面给你写一个 《Java 之 BigDecimal 详解》,内容会涵盖 原理、常用方法、应用场景、注意事项、最佳实践,非常适合入门 + 进阶学习。


Java 之 BigDecimal 详解

一、为什么需要 BigDecimal?

在 Java 中,float 和 double 是浮点数类型,但由于采用 二进制浮点表示,某些小数无法被精确表示。例如:

System.out.println(0.1 + 0.2); // 输出 0.30000000000000004

这在金融计算、金额结算等对精度要求极高的场景下是 不可接受 的。
为了解决这个问题,Java 提供了 BigDecimal —— 任意精度的十进制数类。


二、BigDecimal 的创建方式

  1. 推荐:使用字符串构造函数
BigDecimal bd1 = new BigDecimal("0.1");

  1. 不推荐:使用 double 构造函数(会带入误差)
BigDecimal bd2 = new BigDecimal(0.1); // 有精度问题

  1. 通过 valueOf() 工厂方法(底层转为字符串)
BigDecimal bd3 = BigDecimal.valueOf(0.1); // 推荐

✅ 结论:

  • 金额、精度要求高的场景,优先使用字符串构造或 valueOf()

三、常用方法

1. 基本运算

BigDecimal a = new BigDecimal("10.5");
BigDecimal b = new BigDecimal("2");

System.out.println(a.add(b));      // 加法:12.5
System.out.println(a.subtract(b)); // 减法:8.5
System.out.println(a.multiply(b)); // 乘法:21.0
System.out.println(a.divide(b));   // 除法:5.25

2. 指定除法精度与舍入模式

BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");

BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
System.out.println(result); // 3.33 (保留 2 位小数,四舍五入)

RoundingMode 常见值:

  • HALF_UP → 四舍五入(常用)
  • DOWN → 向下取整
  • UP → 向上取整
  • HALF_EVEN → 银行家舍入法(偶数舍入)

3. 精度控制(保留小数位)

BigDecimal pi = new BigDecimal("3.1415926");
BigDecimal scaled = pi.setScale(2, RoundingMode.HALF_UP);
System.out.println(scaled); // 3.14

4. 比较大小

BigDecimal x = new BigDecimal("1.0");
BigDecimal y = new BigDecimal("1.00");

System.out.println(x.equals(y));        // false(比较值和小数位数)
System.out.println(x.compareTo(y) == 0); // true(仅比较数值)

✅ 推荐用 compareTo() 比较大小,避免因为小数位数不同导致 equals() 返回 false。

5. 转换为其他类型

BigDecimal bd = new BigDecimal("123.45");

System.out.println(bd.intValue());     // 123
System.out.println(bd.doubleValue());  // 123.45
System.out.println(bd.toPlainString()); // "123.45"


四、应用场景

  1. 金融系统 → 金额结算、利率计算、汇率换算
  2. 电商平台 → 商品价格、优惠计算
  3. 科学计算 → 高精度计算
  4. 需要避免浮点误差的场景

五、注意事项

  1. 不要使用 new BigDecimal(double),会引入浮点误差。
    推荐使用 String 或 BigDecimal.valueOf(double)
  2. equals() 和 compareTo() 区别 → 前者考虑小数位数,后者只比较数值。
  3. 除法必须指定精度和舍入模式,否则可能抛 ArithmeticException

六、最佳实践

金额处理推荐工具类:

public class BigDecimalUtils {

    private static final int DEFAULT_SCALE = 2;

    public static BigDecimal add(BigDecimal a, BigDecimal b) {
        return a.add(b);
    }

    public static BigDecimal subtract(BigDecimal a, BigDecimal b) {
        return a.subtract(b);
    }

    public static BigDecimal multiply(BigDecimal a, BigDecimal b) {
        return a.multiply(b);
    }

    public static BigDecimal divide(BigDecimal a, BigDecimal b) {
        return a.divide(b, DEFAULT_SCALE, RoundingMode.HALF_UP);
    }

    public static BigDecimal scale(BigDecimal a) {
        return a.setScale(DEFAULT_SCALE, RoundingMode.HALF_UP);
    }
}


七、总结

  • BigDecimal 是 Java 中处理高精度十进制的首选类
  • 构造时避免 new BigDecimal(double)
  • 除法必须指定精度和舍入方式
  • 比较用 compareTo() 而不是 equals()