面T家,被要求實現一個字符串轉整型數的算法,當時手寫有點遺漏,現在回頭來看看jdk的實現。
常用的是Integer.valueOf方法來實現轉換:
1 public static Integer valueOf(String s) throws NumberFormatException { 2 return Integer.valueOf(parseInt(s, 10)); 3 }
默認會調用parseInt方法進行轉換,參數中的10說明是按照10進制進行轉換的。
看看parseInt方法:
1 public static int parseInt(String s, int radix) 2 throws NumberFormatException 3 { 4 5 if (s == null) { 6 throw new NumberFormatException("null"); 7 } 8 9 if (radix < Character.MIN_RADIX) { 10 throw new NumberFormatException("radix " + radix + 11 " less than Character.MIN_RADIX"); 12 } 13 14 if (radix > Character.MAX_RADIX) { 15 throw new NumberFormatException("radix " + radix + 16 " greater than Character.MAX_RADIX"); 17 } 18 19 int result = 0; 20 boolean negative = false; 21 int i = 0, len = s.length(); 22 int limit = -Integer.MAX_VALUE; 23 int multmin; 24 int digit; 25 26 if (len > 0) { 27 char firstChar = s.charAt(0); 28 if (firstChar < '0') { // Possible leading "+" or "-" 29 if (firstChar == '-') { 30 negative = true; 31 limit = Integer.MIN_VALUE; 32 } else if (firstChar != '+') 33 throw NumberFormatException.forInputString(s); 34 35 if (len == 1) // Cannot have lone "+" or "-" 36 throw NumberFormatException.forInputString(s); 37 i++; 38 } 39 multmin = limit / radix; 40 while (i < len) { 41 // Accumulating negatively avoids surprises near MAX_VALUE 42 digit = Character.digit(s.charAt(i++),radix); 43 if (digit < 0) { 44 throw NumberFormatException.forInputString(s); 45 } 46 if (result < multmin) { 47 throw NumberFormatException.forInputString(s); 48 } 49 result *= radix; 50 if (result < limit + digit) { 51 throw NumberFormatException.forInputString(s); 52 } 53 result -= digit; 54 } 55 } else { 56 throw NumberFormatException.forInputString(s); 57 } 58 return negative ? result : -result; 59 }
首先看到5-17行是邊界檢查:
- 如果字符串s是空指針,直接拋異常
- 如果進制小於最小進制(常量定義為2),拋異常
- 如果進制大於最大進制(常量定義為36),拋異常
接下來19-24行是局部變量定義,這里需要注意一個就是limit被賦值為int表示的最大正整型數的負值,也就是-2147483647。
再往下看到26-38行,如果字符串s長度大於0,那么首先看看首字符
- 如果首字符小於字符0,那么可能是符號 + 或者 - ,要區別對待了
- 如果是符號 - ,說明是個負數,將布爾值變量negative設置為true,並將limit設置為int型整數的下限值,也就是-2147483648
- 如果首字符不是符號 +,說明首字符既不是數字也不是符號,則拋出異常
- 再接下來看,如果首字符是符號 - 或者 +,但是字符串長度只有1,也就是說只有一個符號,那么也是不能夠轉為整型數的,直接拋異常
再往下39-54行
局部變量mulmin賦值為limit除以當前轉換的進制。接下來是一個循環,i代表處理的字符串的位數。
用局部變量digit記錄字符串s第i位數字的相應進制的值,接下來又是一些判斷了:
- 如果digit小於0,拋異常
- 如果result變量小於mulmin,拋異常,這里可以限制之后的乘法操作肯定不溢出;之后result變量乘以當前轉換進制。(如果result小於mulmin也就是limit/radix了,那么后面的乘以radix肯定就會小於limit,對於負數就超過了Integer的范圍,對於正數也是超過了Integer.MAX_VALUE)
- 如果此時result小於limit加上digit,拋異常,這里可以限制之后的減法操作不會溢出;之后result變量減去digit的值。(這個拋異常和上一條原因類似,也是為了防止溢出)
最后58行,如果negative為true,則直接返回result,否則返回負的result。
這個有點意思,如果是負數直接輸出,如果是正數反而是用負數取負,負負得正來表示的。
個人覺得應該是整型數從絕對值來看,負數的范圍比正數大1,如果用result += digit這樣來進行計算的話,那么最小值-2147483648會無法被正確轉換。因為2147483640+8會得到-2147483648,然后再取負數的話,就變成0了。但是使用-=來計算,因為負數的范圍更大,因此正數是可以全部表示出來的,而且不管是+0還是-0都不會有問題,都可以得到數值0。