在 Java 開發中,數字格式化是常見需求。許多開發者會使用 DecimalFormat 來處理小數位數與四捨五入,但有時會遇到預期外的結果。本文將深入探討 DecimalFormat 的運作機制,並提供更可靠的替代方案。
開發者希望將數字格式化為 ###.0000 格式,即保留四位小數並四捨五入。測試代碼如下:
public class FormatTest {
public static void main(String[] args) {
java.text.DecimalFormat df = new java.text.DecimalFormat("###.0000");
java.lang.Double db1 = new java.lang.Double("12.00005");
java.lang.Double db2 = new java.lang.Double("12.00006");
java.lang.Double db3 = new java.lang.Double("12.000055");
java.lang.Double db4 = new java.lang.Double("12.000056");
System.out.println(df.format(db1)); // 輸出 12.0000
System.out.println(df.format(db2)); // 輸出 12.0001
System.out.println(df.format(db3)); // 輸出 12.0001
System.out.println(df.format(db4)); // 輸出 12.0001
}
}
觀察輸出會發現:12.00005 被格式化為 12.0000,而非預期的 12.0001。這是因為 DecimalFormat 預設使用 銀行家四捨五入 模式,當尾數為 5 且前一位為偶數時會向下捨入。
DecimalFormat 繼承自 NumberFormat,其核心邏輯在於 RoundingMode 的設定。預設的 RoundingMode.HALF_EVEN 即為銀行家四捨五入,旨在減少大量數據統計時的偏差。但對於財務或精確計算場景,這往往不是期望行為。
若需標準四捨五入(HALF_UP),有兩種更直觀的方式:
double d = 12.00005;
String result = String.format("%.4f", d);
System.out.println(result); // 輸出 12.0001
String.format 使用標準四捨五入,語法簡潔,適合單純的格式化輸出需求。
BigDecimal bd = new BigDecimal("12.00005");
bd = bd.setScale(4, RoundingMode.HALF_UP);
System.out.println(bd.toString()); // 輸出 12.0001
BigDecimal 允許顯式指定 RoundingMode,且避免浮點數精度問題,是金融計算的首選。
String.format("%.4f", value)BigDecimal 並明確設定 RoundingMode.HALF_UPDecimalFormat,請手動設定 df.setRoundingMode(RoundingMode.HALF_UP)理解四捨五入模式的差異,能避免生產環境中難以排查的精度 Bug。