「不積跬步,無以至千里;不積小流,無以成江海。」—— 荀子《勸學篇》。本文深入解析《編寫高質量代碼:改善 Java 程序的 151 個建議》第 2 章基本型別部分的建議 21 至 25,透過實戰代碼與反面教材,幫助開發者避開基本型別使用中的隱蔽坑洞。
String result = (i % 2 == 1) ? "奇數" : "偶數";
Java 的取餘運算 % 定義為 dividend - dividend / divisor * divisor。負數取餘時,結果帶負號:-1 % 2 == -1,導致 -1 被誤判為偶數。
String result = (i % 2 == 0) ? "偶數" : "奇數";
核心原則: 知其然,更要知其所以然。基本知識的底層實作細節決定正確性。
System.out.println(10.00 - 9.60); // 輸出 0.40000000000000036
0.4 在二進制中為無限循環小數,無法精確表示。格式化輸出雖能掩蓋,但大量累加會產生不可接受的誤差。
DECIMAL 欄位映射首選。public static final int LIGHT_SPEED = 30 * 10000 * 1000; // 300,000,000 long dis2 = LIGHT_SPEED * 60 * 8; // 本意計算 8 光分鐘距離
右側三個 int 先相乘,結果溢位變負數,再隱式轉為 long,終得錯誤結果 -2028888064。
long dis2 = 1L * LIGHT_SPEED * 60 * 8; // 首因子加 L,強制全鏈路長整型運算
最佳實踐: 主動宣告型別(1L、1.0、1f),讓編譯器在最早階段完成擴型,杜絕隱式轉換驚喜。
if (order > 0 && order + cur <= LIMIT) { // LIMIT = 2000, cur = 1000
// 通過檢核
}
攻擊者輸入 Integer.MAX_VALUE (2147483647),order + cur 溢位變負數,條件成立,繞過限額。
Math.addExact() (Java 8+) 或手動檢核 order > LIMIT - cur 避免溢位Math.round(10.5) = 11,Math.round(-10.5) = -10。正負非對稱,長期大量計息會造成銀行持續虧損(每千萬戶每年約損失 10 萬元)。
四捨六入五考慮,五後非零進一,五後為零看奇偶:五前為偶捨去,五前為奇進一。
BigDecimal interest = principal.multiply(rate)
.setScale(2, RoundingMode.HALF_EVEN); // HALF_EVEN 即銀行家捨入
RoundingMode 七種模式對照表:
| 模式 | 行為 | 典型場景 |
|---|---|---|
| UP | 遠離零方向 | 稅務計算 |
| DOWN | 趨近零方向(截斷) | 折扣計算 |
| CEILING | 趨近正無窮 | 債務人有利 |
| FLOOR | 趨近負無窮 | 債權人有利 |
| HALF_UP | 傳統四捨五入 | 一般商業 |
| HALF_DOWN | 五捨六入 | 特定會計準則 |
| HALF_EVEN | 銀行家捨入(統計誤差最小) | 金融、科學計算首選 |
| UNNECESSARY | 要求精確,否則拋出異常 | 嚴格精確場景 |
基本型別看似簡單,實則暗藏 Java 語言設計、JVM 實作、IEEE 754 浮點數標準等深層知識。養成「主動宣告型別、邊界優先測試、金融用 BigDecimal + HALF_EVEN」的肌肉記憶,是寫出健壯代碼的關鍵。