涉及金錢計算,必須使用 java.math.BigDecimal。 絕不可用 float 或 double。
System.out.println(0.1 + 0.2); // 0.30000000000000004
System.out.println(1.03 - 0.42); // 0.6100000000000001
IEEE 754 二進制浮點數無法精確表示許多十進制小數(如 0.1、0.01),導致財務系統出現「分帳不平」、「利息計算偏差」等嚴重錯誤。
// 錯誤:new BigDecimal(0.1) → 0.10000000000000000555...
// 正確:
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal sum = a.add(b); // 0.3 精確
add(subtract(multiply(divide)
// 除法必須指定精度與捨入模式
BigDecimal c = a.divide(b, 10, RoundingMode.HALF_UP); // 保留10位,四捨五入
a.compareTo(b) // 返回 -1/0/1,勿用 equals(會比較 scale)
NumberFormat fmt = NumberFormat.getCurrencyInstance(Locale.TAIWAN);
fmt.setMaximumFractionDigits(2);
System.out.println(fmt.format(amount)); // NT$1,234.56
| 陷阱 | 錯誤寫法 | 正確寫法 |
|---|---|---|
| 建構子傳 double | new BigDecimal(0.1) | new BigDecimal("0.1") 或 valueOf(0.1) |
| 除法不指定精度 | a.divide(b) | a.divide(b, scale, RoundingMode.HALF_UP) |
| 用 equals 比較 | a.equals(b) | a.compareTo(b) == 0 |
| 直接序列化到 JSON | Jackson 預設輸出數字 | 配置 JsonSerialize(using = ToStringSerializer.class) 輸出字串,防前端 JS 精度丟失 |
long 儲存「分」為單位的整數(1 元 = 100 分),運算時用長整數,顯示時除以 100 格式化。金融系統的基石是精確度。BigDecimal 雖稍顯繁瑣,卻是避免資損、合規審計的必要成本。養成「字串建構、除法指定精度、compareTo 比較」三大習慣,即可杜絕 99% 的浮點數 Bug。