您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關java中int轉string與string轉int的效率有什么不同,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
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的效率有什么不同”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。