`Integer.valueOf(String)` 是日常開發高頻呼叫,但傳入非數字字串會拋出 `NumberFormatException`。本文深入 JDK 原始碼,解析 `parseInt` 核心邏輯,揭示其如何處理正負號、基數、非法字符、以及關鍵的**溢位檢測算法**。
Integer.valueOf(String s)
→ new Integer(parseInt(s, 10))
parseInt(String s, int radix) // 核心靜態方法
`Byte.valueOf`、`Short.valueOf` 內部同樣委派 `Integer.parseInt` 後再範圍檢查。
public static int parseInt(String s, int radix) throws NumberFormatException {
// 1. 空值檢查
if (s == null) throw new NumberFormatException("null");
// 2. 基數合法性 (Character.MIN_RADIX=2, MAX_RADIX=36)
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
throw new NumberFormatException("radix ...");
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit, multmin, digit;
// 3. 空字串檢查
if (len > 0) {
char first = s.charAt(0);
if (first == '-') { negative = true; limit = Integer.MIN_VALUE; i++; }
else { limit = -Integer.MAX_VALUE; } // 統一用負數累加避免溢位
// 4. 處理最高位 (首個數字字符)
if (i < len) {
digit = Character.digit(s.charAt(i++), radix);
if (digit < 0) throw NumberFormatException.forInputString(s);
result = -digit; // 負數累加
}
// 5. 核心循環:逐字符累加
while (i < len) {
digit = Character.digit(s.charAt(i++), radix);
if (digit < 0) throw NumberFormatException.forInputString(s);
// 溢位檢測點 1:result * radix 會溢位嗎?
// multmin = limit / radix (負數除法向零取整)
// 若 result < multmin,則 result * radix < limit → 肯定溢位
if (result < multmin) throw NumberFormatException.forInputString(s);
result *= radix;
// 溢位檢測點 2:加上 digit 後會溢位嗎?
// limit + digit 是允許的最小值 (負數)
// 若 result < limit + digit → 溢位
if (result < limit + digit) throw NumberFormatException.forInputString(s);
result -= digit; // 負數累加:result = result*radix - digit
}
} else {
throw NumberFormatException.forInputString(s); // 空字串
}
// 6. 符號還原
if (negative) {
if (i > 1) return result; // 只有 "-" 號時 i==1,拋異常
else throw NumberFormatException.forInputString(s);
} else {
return -result; // 正數取反
}
}
| 輸入 | 結果 | 拋異常位置 |
|---|---|---|
| `"2147483647"` | `MAX_VALUE` | 正常返回 |
| `"2147483648"` | 異常 | 檢測點 2 (加 digit 後溢位) |
| `"21474836471"` | 異常 | 檢測點 1 (乘法溢位) |
| `"-2147483648"` | `MIN_VALUE` | 正常返回 |
| `"-2147483649"` | 異常 | 檢測點 2 |
public static byte parseByte(String s, int radix) {
int i = Integer.parseInt(s, radix); // 先按 int 解析
if (i < Byte.MIN_VALUE || i > Byte.MAX_VALUE)
throw new NumberFormatException("Value out of range: " + s);
return (byte)i; // 窄化轉換
}