首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java String 轉 Integer 深度解析:parseInt 內部實現與溢位檢測

     編輯:Java 相關知識

前言

`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` 後再範圍檢查。

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; // 正數取反
    }
}

關鍵設計精妙點

  1. 統一用負數累加:`Integer.MIN_VALUE` 絕對值比 `MAX_VALUE` 大 1。若用正數累加,`MAX_VALUE * 10` 會溢位;用負數累加,範圍對稱,無需特判。
  2. 預計算 `multmin = limit / radix`:將乘法溢位判斷轉為減法比較,避免實際溢位產生未定義行為。
  3. 兩階段檢測:先檢查乘法是否溢位,再檢查加法是否溢位,覆蓋所有邊界情況。

邊界測試驗證

輸入結果拋異常位置
`"2147483647"``MAX_VALUE`正常返回
`"2147483648"`異常檢測點 2 (加 digit 後溢位)
`"21474836471"`異常檢測點 1 (乘法溢位)
`"-2147483648"``MIN_VALUE`正常返回
`"-2147483649"`異常檢測點 2

Byte/Short 包裝類的額外範圍檢查

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; // 窄化轉換
}

實戰避坑指南

  • Web 參數轉換:HTTP 參數皆為 String,`Integer.valueOf(request.getParameter("id"))` 必須 `try-catch` 或使用 `NumberUtils.toInt` (Apache Commons Lang) 安全轉換。
  • 大數字處理:超出 `int` 範圍請用 `Long.parseLong` 或 `BigInteger`。
  • 基數陷阱:`Integer.parseInt("0xFF", 16)` 需自行去除 `0x` 前綴,標準庫不支援前綴。
  • 效能優化:高頻熱點路徑可考慮手寫無異常解析 (返回 `OptionalInt`),避免異常開銷。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved