解析Java Integer.parseInt(String s, int radix)源码的溢出检测与负数处理疑问
Let's dive into these two key design decisions in Integer.parseInt—they're clever optimizations to handle integer overflow correctly and efficiently.
First, here's the source code we're looking at for reference:
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("s == null"); } if (radix < Character.MIN_RADIX) { throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX"); } if (radix > Character.MAX_RADIX) { throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); } int result = 0; boolean negative = false; int i = 0, len = s.length(); int limit = -Integer.MAX_VALUE; int multmin; int digit; 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); if (len == 1) // Cannot have lone "+" or "-" throw NumberFormatException.forInputString(s); i++; } multmin = limit / radix; while (i < len) { // Accumulating negatively avoids surprises near MAX_VALUE digit = Character.digit(s.charAt(i++), radix); if (digit < 0) { throw NumberFormatException.forInputString(s); } if (result < multmin) { throw NumberFormatException.forInputString(s); } result *= radix; if (result < limit + digit) { throw NumberFormatException.forInputString(s); } result -= digit; } } else { throw NumberFormatException.forInputString(s); } return negative ? result : -result; }
Why keep result negative during calculation?
This is all about handling the asymmetric range of Java's int type. Remember:
Integer.MAX_VALUEis2147483647(2^31 - 1)Integer.MIN_VALUEis-2147483648(-2^31)
The negative side has one more possible value than the positive side. If we tried to accumulate the result as a positive number, we'd hit a problem when parsing the string -2147483648 (the smallest possible int). Its absolute value is 2147483648, which is larger than Integer.MAX_VALUE—so trying to store that as a positive int would cause an overflow before we could negate it.
By keeping result negative from the start:
- We can directly accumulate the full range of possible values without overflowing. For
-2147483648, we just end up withresult = -2147483648, which fits perfectly. - For positive numbers, we just negate the final negative result to get the correct positive value (since
-resultwill be withinInteger.MAX_VALUE).
It's a neat trick to avoid having to handle two separate overflow cases for positive and negative numbers—we just use the larger negative range to cover all possibilities.
How does multmin detect overflow?
multmin is a precomputed threshold to catch overflow before it happens when we multiply result by the radix. Let's break it down:
- First,
limitis set to-Integer.MAX_VALUEfor positive numbers, orInteger.MIN_VALUEfor negative numbers. This is the smallest (most negative) value ourresultcan reach without overflowing. multmin = limit / radix—this is the threshold: ifresultis less thanmultmin, then multiplyingresultbyradixwould make it smaller thanlimit(i.e., overflow).
Take an example for positive numbers (where limit = -2147483647):
- Suppose radix is 10, so
multmin = -2147483647 / 10 = -214748364 - If
resultis-214748365, which is less thanmultmin, thenresult * 10 = -2147483650—this is smaller thanlimit(-2147483647), which is an overflow. We throw an exception before doing the multiplication to avoid this.
After passing that check, we multiply result by radix, then check if result < limit + digit. This catches the case where subtracting the digit would push result below limit. The code does result -= digit, which rearranges to result = result - digit. We need this value to stay above or equal to limit, so rearranged that means result >= limit + digit. If result < limit + digit, then result - digit would be less than limit—another overflow scenario we need to block.
Together, multmin and the second check cover all possible overflow cases during the accumulation process.
内容的提问来源于stack exchange,提问作者tanvi

