Integer的parseInt()方法

宋正兵 on 2020-10-28

Integer.parseInt(String s, int radix) 解析

参数说明:

  • String s:需要解析的字符串,允许携带正负号 '+''-'
  • int radix:字符串中包含数字是 radix进制

返回值: int 类型的十进制整数

比如: Integer.parseInt("1010",2)

意思就是:输出2进制数1010在十进制下的数.

更直白地说: parseInt(String s,int radix)就是求 radix 进制数 s 的十进制数是多少。

平时用到 Integer.parseInt("123") 其实默认是调用了int i =Integer.parseInt("123",10)

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/

if (s == null) {
throw new NumberFormatException("null");
}
// 最小2进制
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
// 最大36进制
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
// 记录符号
boolean negative = false;
int i = 0, len = s.length();
// 设定边界
int limit = -Integer.MAX_VALUE;

if (len > 0) {
// 解决第一个字符是符号 '+' 或者 '-' 的情况
char firstChar = s.charAt(0);
// 若第一个字符不是数字
if (firstChar < '0') { // Possible leading "+" or "-"
// 如果是 '-',则记录字符串所代表的的数字是负数,设定边界
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+') {
// 如果符号是 '+',则无需操作
// 若既不是 '+' 也不是 '-',则抛出异常
throw NumberFormatException.forInputString(s, radix);
}

if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s, radix);
}
i++;
}
int multmin = limit / radix;
int result = 0;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
int digit = Character.digit(s.charAt(i++), radix);
// 如果Character.digit(char ch, int radix)传入的字符 ch 不是 radix 进制所含有的数字,则返回 -1
// 如果result负累积超过了最小值,溢出
if (digit < 0 || result < multmin) {
throw NumberFormatException.forInputString(s, radix);
}
// 所有数字往左挪一位,空缺的一位补0
result *= radix;
// 如果result - digit 小于最小值,溢出
if (result < limit + digit) {
throw NumberFormatException.forInputString(s, radix);
}
// 补上当前位
result -= digit;
}
return negative ? result : -result;
} else {
throw NumberFormatException.forInputString(s, radix);
}
}

判断一个字符是否为正负号

第 27 行判断第一个字符是否为正负号的条件控制语句如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+') {
throw NumberFormatException.forInputString(s, radix);
}

if (len == 1) { // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s, radix);
}
i++;
}

之所以这么设计,是因为在ASCII码表当中,字母 A~z 对应的编码值大于数字 0~9 对应的编码值,只有 firstChar < '0' 才有可能 firstChar 是正号 '+' 或者负号 '-',并且只有当 firstChar 为负号 '-' 时才有必要对数字的符号位进行记录,正号 '+' 的话只需要跳过 firstChar 即可。

冷冷地吐槽:如果直接判断 firstChar 是否为正负号,把不符合要求的字符留给 while 循环中也能被处理,可能源码有自己的应用场景吧。

采用负累积的计算方法目的是避免接近最大值可能发生的意外

Integer 类型大小为 $-2^{31} , 2^{31}-1$,当字符串为正数的时候,负累积只要不小于 $-2^{31}-1$ 就在允许范围内,当字符串为负数时,负累积只要不小于 $-2^{31}$ 就在允许范围内。

学到了什么?

往后遇到需要从字符串中解析出数字的业务场景可以直接利用 Integer.parseInt(String s, int radix) 方法;如果是在做算法题时,可以借鉴判断第一个字符是否为正负号和采用负累积进行计算的方法。