Interger.parseInt(String) Interger.valueOf(String).intValue()
第二種方法可以去看原始碼,實作了第一種方法。
註解大概就是這樣的意思
/** *返回一个包含整数的对象 *指定的{@ String String}的值。 这个说法是 *被解释为表示一个有符号的十进制整数 *就好像这个论据是给予{@link的 * #parseInt(java.lang.String)}方法。 结果是一个 表示整数值的整数对象 *由字符串指定。 * 换句话说,这个方法返回一个{@code Integer} *对象等于以下值: * * <blockquote> * {@code new Integer(Integer.parseInt(s))} * </ blockquote> * * @param是要解析的字符串。 * @返回一个保存值的{整数}对象 *由字符串参数表示。 * @exception NumberFormatException如果字符串不能被解析 *作为一个整数。 */
在valueOf()裡面實作了parseInt()方法。時間對比第二種比第一種快了很多。
Integer.parseInt(str) : 21 Integer.valueOf(str).intValue() : 14
第一種:number ""
第二種方法: string.valueOf()
第三種:.toString()
先說第一種,簡單粗暴。
第二種方法:底層使用的依舊是.toString()方法
第三種就是toString()
上程式碼。
int num = 888888; //(1)num + "" long start = System.currentTimeMillis();//得到开始运行时系统时间 for(int i=0; i<100000; i++){ String str = num + ""; } long end = System.currentTimeMillis();//得到结束运行时系统时间 System.out.println("num + \"\" : " + (end - start)); //(2)String.valueOf(num) start = System.currentTimeMillis(); for(int i=0; i<100000; i++){ String str = String.valueOf(num); } end = System.currentTimeMillis(); System.out.println("String.valueOf(num) : " + (end - start)); //(3)Integer.toString(num) start = System.currentTimeMillis(); for(int i=0; i<100000; i++){ String str = Integer.toString(num); } end = System.currentTimeMillis(); System.out.println("Integer.toString(num) : " + (end - start));
結果就是
num "" : 82
String.valueOf(num) : 32
Integer.toString(num) : 9
經過多次的反覆測試,toString()是最快的,num ""是最慢的,在使用String.valueOf()中原始碼是這樣的。
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
也就是說在使用的時候,不用去判斷所傳的物件是否為null,但是尤其註意,如果傳的為空,則回傳的是一個為null的字串而不是null值,這個地方需要謹記。
相信很多同學在面試時都遇到這樣一個問題,要求封裝一個函數,將String類型轉換成int型別。這個看似簡單的問題其實隱藏著很多細節,要真正封裝好這個函數並不容易。面試官要考察的其實並不是演算法本身的難度,這個問題的演算法其實沒有什麼難度可言,主要要考察的是程式設計師寫程式碼的仔細程度,考慮問題是否全面,也就是說,我們要盡可能的讓程式碼具有魯棒性。下面我們一步步的分析這個問題中隱藏的細節。
首先我們不考慮任何的例外處理,假設函數的呼叫者傳入的資料都是正確的,很容易就可以寫出下面的程式碼:
public int strToInt(String str) { int number = 0; for (int i=0; i<str.length(); i++) { number *= 10; number += (str.charAt(i) - '0'); } return number; }
上面的程式碼將遍歷字串的每一位字符,並將其轉換為對應的整數,然後將其一一融入整形資料number中。
如果你給面試官提交的是這樣一份程式碼,結果肯定不會滿意。因為你沒有考慮到程式的魯棒性,我們封裝的函數相當於API接口,是提供給所有開發者調用的,難免其他開發者不會傳入一些奇怪的參數,而這段程式碼對異常參數沒有做任何處理,一旦傳入異常參數,程式將直接崩潰。下面我們一步步來完善這個函數,提高其穩健性。
public int strToInt(String str) throws NumberFormatException{ if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } int number = 0; for (int i=0; i<str.length(); i++) { number *= 10; number += (str.charAt(i) - '0'); } return number; }
首先我們字串是否為空或是否為空的字串,如果是,則直接拋出異常,這裡我們使用的是Java封裝好的異常類NumberFormatException,當然我們也可以自己封裝異常類,面試官要考察的不是對異常類的封裝,而是你要知道要處理異常情況。
這個我們最好提前問一下面試官,有沒有可能傳入的是負數,當為正數時,是否允許帶符號位,如果是的話,我們就要針對符號位元進行處理,負數的第一個字元是“-”,我們只要判斷第一個字元是否為“-”就可以知道傳入的是否為負數了,如果正數允許帶符號位,那邊第一個字元有可能是“ ”,我們也要做對應的處理:
public int strToInt(String str) throws NumberFormatException{ if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } boolean negative = false; // negative为true表示是负数,反之为正数 int pos = 0; if (str.charAt(0) == '-') { // 如果为负数 negative = true; pos++; // 调过第一位符号位 } else if (str.charAt(0) == '+') { pos++; // 调过第一位符号位 } int number = 0; while (pos < str.length()) { number *= 10; number += (str.charAt(pos) - '0'); pos++; } return negative ? -number : number; // 如果为负数则返回对应的负数 }
函數的呼叫者可能會傳入一下亂七八糟的字串,例如“abc23123”,針對這種情況我們也要做對應的處理,應該給呼叫者拋出一個異常,告知其傳入的字串是非法字串:
public int strToInt(String str) throws NumberFormatException{ if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } boolean negative = false; // negative为true表示是负数,反之为正数 int pos = 0; if (str.charAt(0) == '-') { // 如果为负数 negative = true; pos++; // 调过第一位符号位 } else if (str.charAt(0) == '+') { pos++; // 调过第一位符号位 } int number = 0; while (pos < str.length()) { if (str.charAt(pos) >= '0' && str.charAt(pos) <= '9') { // 只有字符在'0'到'9'的范围内,才算正确的字符 number *= 10; number += (str.charAt(pos) - '0'); pos++; } else { throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误 } } return negative ? -number : number; // 如果为负数则返回对应的负数 }
呼叫者傳入的字串可能是一個很長的字串,轉換為整數可能超出了整數的儲存範圍,例如“12345678674324334” ,在這種情況下,我們要拋出一個異常告知呼叫者傳入的字串超出了整形的範圍:
public int strToInt(String str) throws NumberFormatException{ if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } boolean negative = false; // negative为true表示是负数,反之为正数 int pos = 0; if (str.charAt(0) == '-') { // 如果为负数 negative = true; pos++; // 调过第一位符号位 } else if (str.charAt(0) == '+') { pos++; // 调过第一位符号位 } int limit = negative ? (-Integer.MIN_VALUE) : Integer.MAX_VALUE; int mult = limit / 10; // 记录最大数/10,让number和这个数比较,如果大于它,则number * 10肯定也就大于最大数 int number = 0; while (pos < str.length()) { if (str.charAt(pos) >= '0' && str.charAt(pos) <= '9') { // 只有字符在'0'到'9'的范围内,才算正确的字符 if (number > mult) {// 让number和mult比较,如果大于它,则number * 10肯定也就大于最大数 throw new NumberFormatException("input string beyond int size"); } number *= 10; int digit = str.charAt(pos) - '0'; if (number > limit - digit) { // 这里不能用number + digit > limit来判断,因为number + digit可能超出整数的存储范围,相加后的数可能是一个负数,但是limit - digit肯定不会超出 throw new NumberFormatException("input string beyond int size"); } else { number += digit; } pos++; } else { throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误 } } return negative ? -number : number; // 如果为负数则返回对应的负数 }
上面的程式碼中,我們判斷number是否會超出最大整數時首先是先讓其(最大整數/10)的值比較,而不是讓其乘以10與最大整數比較,這是因為number * 10如果超出了整數範圍,則會造成數據溢出,其得到的值可能是一個負數,而(最大整數/10)的值是不會資料溢出的,這也是一個小細節。可能你以為這樣這個函數就完美了,但是現在我要告訴你,上面的寫法是錯的。
为什么呢?这要从整数的范围说起,整数的取值范围是(-2^31)至(2^31 - 1),从绝对值的角度看,最小负数相比于最大正数大1。所以上面代码中(-Integer.MIN_VALUE)会超出整形的范围,造成数据溢出,也就是说上面的代码对负数最小范围的限制的处理是错误的。那么怎么解决这个问题呢?
我们换个角度思考,最小负数的绝对值比最大正数的绝对值大1,那(-Integer.MAX_VALUE)的值肯定不会超出整数的范围,我们现在的程序是以正数的方式处理,如果反过来已负数的方式处理,问题不就解决了吗?修改代码如下:
public int strToInt(String str) throws NumberFormatException{ if (str == null || str.contentEquals("")) { // 如果传入的字符串为空对象或者传入的字符串为空字符串,则抛出异常 throw new NumberFormatException("null or empty string"); // 这里直接利用java封装好的异常类,当然我们也可以自己封装异常类,面试官要考察的不是对异常类的封装,而是你要知道要处理异常情况 } boolean negative = false; // negative为true表示是负数,反之为正数 int pos = 0; if (str.charAt(0) == '-') { // 如果为负数 negative = true; pos++; // 调过第一位符号位 } else if (str.charAt(0) == '+') { pos++; // 调过第一位符号位 } int limit = negative ? Integer.MIN_VALUE : (-Integer.MAX_VALUE); int mult = limit / 10; int number = 0; while (pos < str.length()) { if (str.charAt(pos) >= '0' && str.charAt(pos) <= '9') { // 只有字符在'0'到'9'的范围内,才算正确的字符 if (number < mult) { throw new NumberFormatException("input string beyond int size"); } number *= 10; int digit = str.charAt(pos) - '0'; if (number < limit + digit) { throw new NumberFormatException("input string beyond int size"); } else { number -= digit; } pos++; } else { throw new NumberFormatException("invalid string"); // 当字符是其他字符时,抛出异常告知调用者传入的字符串错误 } } return negative ? number : -number; }
OK,现在我们把能够想到的异常情况处理了。再来考虑一个问题,为什么整形数据的范围是(-2^31)至(2^31 - 1),最小负数的绝对值比最大正数的绝对值要大1呢?
我们知道,一个int类型占四个字节,也就是32位,其中第一位是符号位,符号位为0表示正数,为1表示负数,其余31位表示数值。正常来说int类型的数据范围应该是(-2^31-1)到(2^31-1),为什么负数会多一位呢?
我们首先看一下Java代码中对Integer.MAX_VALUE和Integer.MIN_VALUE的定义:
/** * A constant holding the minimum value an {@code int} can * have, -2<sup>31</sup>. */ public static final int MIN_VALUE = 0x80000000; /** * A constant holding the maximum value an {@code int} can * have, 2<sup>31</sup>-1. */ public static final int MAX_VALUE = 0x7fffffff;
我们知道,在计算机中,数据都是以二进制的形式存储的,比如,数字10,其二进制形式就是1010。
一个字节有8位,每位可以存储一个01字符,byte类型占1个字节,也就是8位,其中,最高位是符号位,用来表示数值是正数还是负数,符号位为0表示正数,符号位为1表示负数。我们先来看一下原码、反码、补码的定义:
原码:符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。
反码:正数的反码是其本身;负数的反码是在其原码的基础上, 符号位不变,其余各个位取反。
补码:补码的表示方法是:正数的补码就是其本身;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1。 (即在反码的基础上+1)
正数的原码、反码、补码都是其本身;负数的反码是在其原码的基础上,符号位不变,其余个位取反,负数的补码是其反码的基础上+1。
举例说明(下面都以byte类型进行举例):
数据 | 原码 | 反码 | 补码 |
10 | 00001010 | 00001010 | 00001010 |
-10 | 10001010 | 11110101 | 11110110 |
计算机中,数据都是以补码的形式存储的。为什么要以补码的形式存储呢?有两个原因:
1、如果数值以补码的形式保存,对一个数进行求补运算,可以得到其相反值
求补运算:将一个数(包括正数和负数)所有二进制位(包括符号位和数值位)取反,然后在最低位加上1。
为什么对一个数进行求补运算,可以得到其相反值呢?我们先来分析一下求补运算的定义,现将所有的二进制取反,然后+1,首先一个数和它所有位取反得到的数相加,其结果肯定是11111111,这是因为它们每一位都不一样,然后将结果+1,即11111111 + 1,结果是1 00000000,最高位的1已经溢出,换种方式说,如果以f(n)表示对n进行求补运算,那么对于任意的范围内的数,可以得到:
n + f(n) = 1 00000000
即
f(n) = 1 00000000 - n
而对于一个正数来说,对其进行求补运算其实得到的就是它的相反数的补码(负数的补码符号位保持不变,其他为全部取反再+1,因为正数和负数的符号位本来就不一样,所以对一个正数进行求补其实得到的就是它的相反数的补码)。
那么对于一个负数来说呢?对其进行求补运算是否能够得到其对应的正数的补码呢?
假设n>0,根据上面可知:
f(n) = 1 00000000 - n
对f(n)进行求补运算,有:
f(f(n)) = f(1 00000000 - n) = 1 00000000 - (1 00000000 - n) = n
其中,1 00000000 - n表示n对应负数的补码,对其进行求补运算得到的就是n,正数的补码就是其原码。
由上可知:如果数值以补码的形式保存,对一个数进行求补运算,可以得到其相反值,即:f(n) = -n
2、方便减法运算
如果数值以补码的方式存储,可以将减法变为加法,省去了减法器,通过上面的推导,如果数据以补码的方式存储,以f(n)表示对n进行求补运算,可以得到:
f(n) = -n
那么现在我们需要计算m - n,应该要怎么计算呢?如果以补码的方式存储,那么就有:
m - n = m + (-n) = m + f(n)
也就是说,减去一个数只需要加上对其进行求补运算后得到的值即可。
3、使用补码存储数据,可以对任意的两个数直接进行相加运算,不用考虑符号位
4、通过补码形式存储,规定10000000对应的负数的最小值,也就是-128。
由上面可知,如果是byte类型,数据范围应该为[-128,127],最小负数要比最大正数多一位。
以上是java中int轉string與string轉int的效率有什麼不同的詳細內容。更多資訊請關注PHP中文網其他相關文章!