java把字符串转换成整数_【Java】将字符串转化为整数

前几天面试遇到这个问题:在Java中如何将字符串转化为整数,当时too young too naive,随便回答了一下。今天跑去看Java源码中paresInt函数的写法,Oh my god!其实不看也能写出来,但是我觉得源码中的实现更好。下面贴出源码顺道分析一下:

1 /*@param s the {@code String} containing the integer2 * representation to be parsed3 * @param radix the radix to be used while parsing {@code s}.4 * @return the integer represented by the string argument in the5 * specified radix.6 * @exception NumberFormatException if the {@code String}7 * does not contain a parsable {@code int}.8 */

9 public static int parseInt(String s, intradix)10 throwsNumberFormatException11 {12 /*

13 * WARNING: This method may be invoked early during VM initialization14 * before IntegerCache is initialized. Care must be taken to not use15 * the valueOf method.16 */

17

18 if (s == null) {19 throw new NumberFormatException("null");20 }21

22 if (radix

24 " less than Character.MIN_RADIX");25 }26

27 if (radix >Character.MAX_RADIX) {28 throw new NumberFormatException("radix " + radix +

29 " greater than Character.MAX_RADIX");30 }31

32 int result = 0;33 boolean negative = false;34 int i = 0, len =s.length();35 int limit = -Integer.MAX_VALUE;36 intmultmin;37 intdigit;38

39 if (len > 0) {40 char firstChar = s.charAt(0);41 if (firstChar < '0') { //Possible leading "+" or "-"

42 if (firstChar == '-') {43 negative = true;44 limit =Integer.MIN_VALUE;45 } else if (firstChar != '+')46 throwNumberFormatException.forInputString(s);47

48 if (len == 1) //Cannot have lone "+" or "-"

49 throwNumberFormatException.forInputString(s);50 i++;51 }52 multmin = limit /radix;53 while (i

55 digit = Character.digit(s.charAt(i++),radix);56 if (digit < 0) {57 throwNumberFormatException.forInputString(s);58 }59 if (result

首先参数:1)第一个是String,表示需要被转化的字符串;2)第二个是进制,表示字符串需要当做什么进制的字符串去解析。

18-30行表示:如果是空字符串,或者进制低于能解析的最小进制(2)或者高于能解析的最大进制(36),则抛出异常;

接下来看40-51行:这里主要是根据第一个字符去判断字符串代表的数字是正的还是负的,通过flag negative标记。

剩余的部分比较复杂,先解释一下基本思想:取出字符串中的每一位字符,按照进制radix转化为数字,倘若不是数字,则返回值为-1,抛出异常。到这里都很好理解,包括39行的判断,都是很基本的。其实我一开始想的是,可以检测字符串的长度n,然后直接得出最后正数结果相应位置上的数字,大体算法如下:

1 public static intparseInt(String s){2 int result = 0;3

4 int length =s.length();5

6 for(int index = 0; index < length; index ++){7 int number = s.charAt(index) - '0';//获取字符代表的数字8 result += number * Math.pow(10, length - index - 1);9 }10

11 returnresult;12 }

这里是简写,很多情况包括正负都没有考虑,并且默认是10进制,这是我的想法。但是我发现源码的想法并非如此,抽象出来大致如下:

1 public static intparseInt(String s){2 int result = 0;3

4 int length =s.length();5

6 for(int index = 0; index < length; index ++){7 int number = s.charAt(index) - '0';8 result *= 10;9 result +=number;10 }11

12 returnresult;13 }

这样子写,减少了很多的乘法,原先在进位上需要做(1+n)n/2次乘法,后面则只需要n次,这是一次改进。

接着代码要解决的是另外一个很重要的问题,Java中整数值都是32位的,它是有范围的。我们需要验证字符串转化之后是不是在这个范围以内,即[Integer.MIN_VALUE, Integer.MAX_VALUE]。这就是59-65行要做的事情。

正数最大值可以达到2147483647,如果给出字符串“2147483648”,则解析出来肯定超范围。如何检测呢,根据上面的算法,假设解析到214748364,我们打断解析最后一位,可以通过Integer.MAX_VALUE-214748364 * radius <= 下一个digit来判断,如果表达式成立,则可以继续解析,否则不可以解析。但是这样想是有局限的,比如我们实际要解析的字符串是“89”,则可以看到其实上面那个表达式并不成立,但是89明显小于最大范围,可以解析,这里如何解决呢?

我们可以这样:将范围同时缩小一个量级,即解析出来的结果不去和2147483647比较,而是和214748364比较,当超出这个范围的时候,我们再使用上面的表达式进行判断。负数亦然。按照这个思想,我将上面的代码改了一下:

1 public static intparseInt(String s){2 int result = 0;3 int limit =Integer.MAX_VALUE;4 int upLimit = limit / 10;5

6 int length =s.length();7

8 for(int index = 0; index < length; index ++){9 int number = s.charAt(index) - '0';10

11 if(result > upLimit)//这个时候乘以result * 10,必然大于Integer.MAX_VALUE

12 return -1;13

14 if(result == upLimit && (limit - result * 10)

17 result *= 10;18 result +=number;19 }20

21 returnresult;22 }

注意代码中11行的注释。我使用几个边界数字测试的结果是正确的,这里同样默认是正数,最大只能解析到2147483647。Java的实现和这个就差不多了,但是Java奇怪的地方是在于使用减法而非加法,可以详细对比一下Java源码的66行和上面我的代码的第18行。Java的这种想法在其代码的第71行也有表现,我们可以看到,当值是负数的时候,直接返回result,否则是要取负数的。

Java源码在52行设置了multmin,59-61行代码和我的代码的11-12行作用一样,62-65行则和我代码的14-15行代码一样。但是我的代码这样写,是需要分类讨论的,即需要分为正负数去讨论。Java的精妙在于:将传入的字符串去掉正负号,根据正负设定下限,然后使用同一种方法去解析剩余的字符串,而可以不管正负!

在Java的源码中,如果传入的是正数,则下限是-Integer.MAX_VALUE,如果是负数,则下限是Integer.MIN_VALUE,然后使用negative去判断返回的时候是不是应该添加负号。中间则按照上面的思路,59-61行用来确保result * radix不会超出界限,62-65行则用来判断最终是否超出界限。注意,我的代码和Java的代码其实都注意到一点,Java代码中63行比较符合思维的写法应该是:

1 if (result - digit < limit) {

但是Java并没有这样写,而是写成源码中的形式,我的代码14行也是如此,这里的主要原因是,这行代码本身就是检测result-digit是否超出界限的,如果按照上面的写法,result-digit如果超出界限,则会报错,但是按照Java源码的写法,limit+digit是肯定在表示范围内的!

另外,注意,这里并不存在统一设置上限的写法,因为-Integer.MIN_VALUE > Integer.MAX_VALUE!

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页

打赏作者

46649676737

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值