在 Java 開發中,double 和 float 等浮點類型雖然方便,但存在精度缺失問題。例如 0.1 + 0.2 的結果並非精確的 0.3,而是 0.30000000000000004。這在財務、科學計算等對精度要求極高的場景下是不可接受的。
Java 在 java.math 包中提供了 BigDecimal 類,專門用於處理超過 16 位有效數字的精確運算。它以不可變對象的形式封裝數值,支援任意精度的整數、小數運算,是高精度計算的首選方案。
| 構造器 | 說明 |
|---|---|
BigDecimal(String val) | 推薦使用,根據字符串表示創建對象,避免精度損失 |
BigDecimal(double val) | 根據 double 值創建,可能帶入浮點誤差 |
BigDecimal(BigInteger val) | 根據 BigInteger 創建 |
BigDecimal(BigInteger unscaledVal, int scale) | 根據無標度值和標度創建 |
由於 BigDecimal 是不可變對象,所有運算方法都會返回新對象,原對象不變:
add(BigDecimal augend):加法subtract(BigDecimal subtrahend):減法multiply(BigDecimal multiplicand):乘法divide(BigDecimal divisor, int scale, RoundingMode roundingMode):除法(需指定精度和舍入模式)setScale(int newScale, RoundingMode roundingMode):設置精度compareTo(BigDecimal val):比較大小// ❌ 錯誤示範:double 構造器引入精度誤差
BigDecimal bd1 = new BigDecimal(0.1); // 實際值:0.10000000000000000555...
// ✅ 正確示範:字符串構造器保證精度
BigDecimal bd2 = new BigDecimal("0.1"); // 精確值:0.1
核心原則:永遠使用 BigDecimal(String) 構造器創建對象。若數值源自數據庫或前端傳入,應先轉為字符串再構造。
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalDemo {
public static void main(String[] args) {
// 創建高精度數值
BigDecimal price = new BigDecimal("89.1234567890123456789");
BigDecimal quantity = new BigDecimal("1000");
// 乘法運算
BigDecimal total = price.multiply(quantity);
System.out.println("總價:" + total);
// 輸出:89123.4567890123456789000
// 除法運算(保留 2 位小數,四捨五入)
BigDecimal unitPrice = total.divide(quantity, 2, RoundingMode.HALF_UP);
System.out.println("單價:" + unitPrice);
// 輸出:89.12
}
}
BigDecimal bigNumber = new BigDecimal("89.1234567890123456789");
// ⚠️ 轉為 double 會丟失精度
double dValue = bigNumber.doubleValue();
System.out.println(dValue); // 輸出:89.12345678901235 (精度已損失)
// ✅ 保持 BigDecimal 類型進行運算,僅在最終展示時轉字符串
String displayValue = bigNumber.toPlainString(); // 不使用科學計數法
NumberFormat 可直接接受 BigDecimal 參數,實現貨幣、百分比等格式化:
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Locale;
public class FormatDemo {
public static void main(String[] args) {
BigDecimal loanAmount = new BigDecimal("129876534219876523.12");
BigDecimal interestRate = new BigDecimal("0.08765");
BigDecimal interest = loanAmount.multiply(interestRate);
// 貨幣格式化(自動帶分組分隔符和貨幣符號)
NumberFormat currency = NumberFormat.getCurrencyInstance(Locale.TRADITIONAL_CHINESE);
// 百分比格式化
NumberFormat percent = NumberFormat.getPercentInstance();
percent.setMaximumFractionDigits(3); // 保留 3 位小數
System.out.println("貸款金額:" + currency.format(loanAmount));
// 輸出:貸款金額:NT$129,876,534,219,876,523.12
System.out.println("利率:" + percent.format(interestRate));
// 輸出:利率:8.765%
System.out.println("利息:" + currency.format(interest));
// 輸出:利息:NT$11,384,239,549,149,661.69
}
}
divide(BigDecimal) 遇無限循環小數會拋 ArithmeticException,必須用 divide(BigDecimal, int, RoundingMode)。equals() 比較值和標度,new BigDecimal("1.0").equals(new BigDecimal("1.00")) 為 false。比較大小請用 compareTo()。a.add(b) 不會修改 a,必須接收返回值 a = a.add(b)。BigDecimal 比原生類型慢,可考慮 long 存儲分/厘為單位的整數運算。BigDecimal 是 Java 處理高精度數值運算的標準工具。掌握其核心原則——字符串構造、不可變運算、除法指定精度、格式化輸出——即可在財務系統、電商訂單、科學計算等場景中構建可靠的數值處理邏輯。