在 Android 開發中,金額、比率、測量數據常需精確控制小數位數。本文系統介紹 DecimalFormat、String.format、BigDecimal 三大方案,針對您的「只保留小數點後兩位」需求提供最佳實踐。
累加商品總價:
Double mGTotal = ...; // 例:179.257856
// 需顯示:179.25 (非四捨五入,直接截斷?或四捨五入?)
關鍵澄清:「只顯示小數點後兩位」通常指四捨五入 (179.26),而非截斷 (179.25)。您的範例輸出 179.25 暗示需截斷,但財務場景多為四捨五入。下文將涵蓋兩種情況。
// 四捨五入模式 (標準財務)
DecimalFormat dfRound = new DecimalFormat("#.##"); // 或 "0.00" 強制兩位
String result1 = dfRound.format(179.257856); // "179.26"
// 截斷模式 (直接捨去)
DecimalFormat dfTruncate = new DecimalFormat("#.##");
dfTruncate.setRoundingMode(RoundingMode.DOWN); // 關鍵:設定截斷模式
String result2 = dfTruncate.format(179.257856); // "179.25"
// 強制顯示兩位小數 (含尾數 0)
DecimalFormat dfFixed = new DecimalFormat("0.00");
dfFixed.setRoundingMode(RoundingMode.HALF_UP);
String result3 = dfFixed.format(100.1); // "100.10"
| 模式 | 輸入 | 輸出 | 說明 |
|---|---|---|---|
#.## | 179.257856 | 179.26 | 最多兩位,整數部不補 0 |
0.00 | 179.257856 | 179.26 | 固定兩位,不足補 0 |
#,##0.00 | 1234.5 | 1,234.50 | 含千分位分隔符 |
¥#,##0.00 | 1234.5 | ¥1,234.50 | 貨幣符號前綴 |
HALF_UP:四捨五入 (預設),1.5 → 2, -1.5 → -1DOWN:向零截斷 (您的範例需求),1.99 → 1, -1.99 → -1UP:遠離零進位,1.01 → 2HALF_EVEN:銀行家算法 (統計學推薦)// 四捨五入,固定兩位
String result = String.format(Locale.getDefault(), "%.2f", 179.257856); // "179.26"
// 截斷需配合 BigDecimal
String truncated = String.format("%.2f",
new BigDecimal(179.257856).setScale(2, RoundingMode.DOWN)); // "179.25"
注意:String.format 依賴 Locale,德語環境下小數點為逗號。財務顯示建議指定 Locale.US。
核心原則:浮點運算不可用於金融計算。您的代碼使用 Double 累加已產生精度誤差:
// 錯誤示範
Double total = 0.1 + 0.2; // 0.30000000000000004
// 正確:全程使用 BigDecimal
BigDecimal total = BigDecimal.ZERO;
for (Item item : items) {
total = total.add(new BigDecimal(item.getPrice())); // 傳入 String 或長整數分
}
// 格式化輸出
String display = total.setScale(2, RoundingMode.HALF_UP).toPlainString();
@Override
protected void onResume() {
super.onResume();
if (Constants.mItem_Detail.isEmpty()) return;
// 1. 使用 BigDecimal 避免浮點誤差
BigDecimal grandTotal = BigDecimal.ZERO;
for (Map detail : Constants.mItem_Detail) {
String priceStr = detail.get(SingleProductActivity.KEY_TOTAL);
if (priceStr != null) {
grandTotal = grandTotal.add(new BigDecimal(priceStr));
}
}
// 2. 格式化:四捨五入保留兩位 (財務標準)
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.HALF_UP);
String displayText = df.format(grandTotal);
// 3. 更新 UI
mTxtViewGrandTotal.setText(displayText);
myTextVeiwGrandTotal.setText(displayText); // 注意:變數名拼寫錯誤 myTextVeiwGrandTotal
mItems.setText(String.valueOf(Constants.mItem_Detail.size()));
}
DecimalFormat 非執行緒安全,每次使用建議 new 實例,或使用 ThreadLocal 緩存String.formatBigDecimal 物件創建開銷較大,大量計算可考慮以「分」為單位用 long 運算針對「保留兩位小數」:
DecimalFormat("0.00") + RoundingMode.HALF_UP (四捨五入) 或 DOWN (截斷)BigDecimal 或整數分單位Locale.US 確保小數點一致性您的原始代碼只需在 setText 前加上格式化即可修復顯示問題,但強烈建議同步修正計算層精度隱患。