漲見識!Java String轉(zhuǎn)int還有這種寫法
之前我寫了一篇《老師,你確定Java注釋不會被執(zhí)行嗎》,結(jié)果文章在知乎小火了一把,將近 10 萬人閱讀。有愛裝逼的同行批評說,標題夸大了;同時,也有很多初學(xué)者表示,漲見識了,之前從來不知道這個知識點,這下學(xué)到了。
必須得承認一點,我寫的大多數(shù)技術(shù)文章都是針對初學(xué)者的,因為我覺得他們最需要幫助,這也是我一直堅持分享的初衷。
我也不喜歡寫那些高深的文章,費時間耗精力,受眾也小。就拿我們學(xué)過的古詩來說吧,“鵝鵝鵝,曲項向天歌”,“一去二三里,煙村四五家”,我就覺得挺好的。沒必要都去搞陽春白雪,最后搞得曲高和寡,對吧?
那這次來分享一個新的知識點,我敢賭一包衛(wèi)龍辣條(打錢來),很多同學(xué)不一定知道。
在 Java 中,String(字符串) 和 int(整形) 是兩種不同的數(shù)據(jù)類型,字符串可以把許多字符串起來,整形嘛——就是整形了。
(同學(xué)們可能會疑惑,這個知識點我能不知道,別蒙我好不好?繼續(xù)往下看唄。吃大餐之前,還能不來點小吃或者涼菜?)
有時候,字符串可以單純包含一些數(shù)字,比如說“123”。大家應(yīng)該都見過,當(dāng)一些操作需要你輸入手機驗證碼的時候,大部分要求輸入的都是 6 位或者 4 位的隨機數(shù)字,它們傳遞到服務(wù)器端的時候,最初的形式都是字符串類型的,然后可能再轉(zhuǎn)成整形做一些處理。
對于 Java 來說,不能直接通過“+”操作符來使兩個字符串類型的數(shù)字相加,來看下面的例子。
- String a = "100";
- String b = "50";
- String c = a+b;
- System.out.println(c);
程序輸出的結(jié)果是 10050,而不是 150。對于字符串來說,“+”操作符是用來串聯(lián)的,而不是用來相加的。
(同學(xué)們可能又要催了,這個知識點我也知道啊!馬上馬上,重點馬上就來。)
那就有必要先把字符串轉(zhuǎn)成整形再來做運算了,常見的做法有兩種:
第一種,使用 Integer.valueOf(),它將返回一個包裝器類型 Integer,當(dāng)然可以通過自動拆箱的方式將其轉(zhuǎn)成 int 類型。
- String a = "100";
- String b= "50";
- int A = Integer.valueOf(a);
- int B = Integer.valueOf(b);
- int c = A+B;
- System.out.println(c);
程序輸出結(jié)果如下所示:
- 150
第二種,使用 Integer.parseInt(),它將返回一個基本數(shù)據(jù)類型 int。
- String a = "100";
- String b= "50";
- int A = Integer.parseInt(a);
- int B = Integer.parseInt(b);
- int c = A+B;
- System.out.println(c);
程序輸出結(jié)果如下所示:
- 150
這兩種方式,優(yōu)先推薦第二種,因為不涉及到自動拆箱,性能更佳。
(同學(xué)們可能急不可耐了,就這?好了,現(xiàn)在重點真的來了)
那除了上面這兩種方式,同學(xué)們還能想到第三種嗎?把字符串轉(zhuǎn)成整形。是不是突然感覺腦袋里有點空?
空就對了,本篇文章最漲見識的時候,它來了!步履蹣跚地來了!
- /**
- * @author 沉默王二,一枚有趣的程序員
- */
- public class String2IntDemo {
- public static void main(String[] args) {
- String a = "100";
- String b = "50";
- int A = string2int(a);
- int B = string2int(b);
- int c = A + B;
- System.out.println(c);
- }
- public static int string2int(String s) {
- int num = 0;
- int pos = 1;
- for (int i = s.length() - 1; i >= 0; i--) {
- num += (s.charAt(i) - '0') * pos;
- pos *= 10;
- }
- return num;
- }
- }
這段程序輸出的結(jié)果同樣是 150。那眼睛雪亮的同學(xué)可能就發(fā)現(xiàn)了,string2int()方法到底是個什么樣的神奇方法,還有把字符串轉(zhuǎn)成整形的功效?
首先,必須得普及一點常識,同學(xué)們需要對 ASCII 碼有一點了解,就是所有的字符都有識別它們的代碼——這代碼就是 ASCII 碼。
基于這一點,所有數(shù)字型的字符減去字符‘0’,將會得到該字符的絕對值,是一個整數(shù)。
- String s = "520";
- System.out.println(s.charAt(2) - '0');
- System.out.println(s.charAt(1) - '0');
- System.out.println(s.charAt(0) - '0');
輸出結(jié)果如下所示:
- 0
- 2
- 5
字符串“520”的長度為 3,也就是說,下標為 2 的位置是字符‘0’——數(shù)字 520 的個位數(shù);下標為 1 的位置是字符‘2’——數(shù)字 520 的十位數(shù);下標為 0 的位置是字符‘5’——數(shù)字 520 的百位數(shù)。
那有些機靈點的同學(xué)可能就想到了,通過一個 for 循環(huán),遍歷一下字符串,然后計算出當(dāng)前位置上的整數(shù)值,個位數(shù)乘以 1,十位數(shù)乘以 10,百位數(shù)乘以 100,然后再加起來,就是字符串對應(yīng)的整數(shù)值了。
沒錯,沒錯,string2int() 方法就是這么做的,如果參數(shù)是字符串“520”,那返回的結(jié)果就是整形 520;如果參數(shù)是字符串“100”,那返回的結(jié)果就是整形 100;如果參數(shù)是字符串“50”,那返回的結(jié)果就是整形 50。
如果你是一名有追求的程序員,那么對于 Integer.valueOf() 和Integer.parseInt() 都不會太滿意,因為這只是拿別人的輪子來用。而自定義方法 string2int() 就屬于從頭到尾的造輪子了。一想到這,是不是感覺自己開始變牛逼了?
其實,如果你肯扒拉源碼的話,就會恍然大悟。
先來看 Integer.valueOf() 方法:
- public static Integer valueOf(String s) throws NumberFormatException {
- return Integer.valueOf(parseInt(s, 10));
- }
內(nèi)部調(diào)用的其實就是 int parseInt(String s, int radix) 方法。
再來看 Integer.parseInt() 方法:
- public static int parseInt(String s) throws NumberFormatException {
- return parseInt(s,10);
- }
內(nèi)部調(diào)用的也是 int parseInt(String s, int radix) 方法,基數(shù) radix 參數(shù)都是 10——同學(xué)們是不是猜到了什么?
對,你猜的八九不離十,再來看一下 int parseInt(String s, int radix) 方法的源碼:
- 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");
- }
- 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");
- }
- 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);
- if (digit < 0 || result < multmin) {
- throw NumberFormatException.forInputString(s, radix);
- }
- result *= radix;
- if (result < limit + digit) {
- throw NumberFormatException.forInputString(s, radix);
- }
- result -= digit;
- }
- return negative ? result : -result;
- } else {
- throw NumberFormatException.forInputString(s, radix);
- }
- }
1)parseInt() 方法判斷了 null 的情況,認為格式不正確。
2)然后判斷了基數(shù) radix 的情況,不能小于 2,不能大于 36。
3)if (len > 0) 判斷了字符串長度的情況,如果為空“”,也認為格式不正確。
4)再然后判斷首個字符 s.charAt(0),如果是負號“-”則認為當(dāng)前字符串是一個負數(shù);如果不是正號“+”,則認為格式不正確;如果只有一個負號或者正號,也認為格式不正確。
總之,就是比我們的自定義方法 string2int() 更嚴謹。
5)使用 while 循環(huán),配合更專業(yè)的 Character.digit(s.charAt(i++), radix) 計算出每個位置上字符對應(yīng)的數(shù)值,然后和基數(shù) radix 進行相乘后使用累減的方式計算出最后的數(shù)值。
和 string2int() 有點不同,但整體上思路是一致的。
我們也可以對 string2int() 方法再完善一下,使其滿足負數(shù)的情況:
- public class S2IDemo {
- public static void main(String[] args) {
- String a = "-100";
- String b = "50";
- int A = string2int(a);
- int B = string2int(b);
- int c = A + B;
- System.out.println(c);
- }
- public static int string2int(String s) {
- boolean negative = false;
- char firstChar = s.charAt(0);
- if (firstChar == '-') {
- negative = true;
- s = s.substring(1);
- }
- int num = 0;
- int pos = 1;
- for (int i = s.length() - 1; i >= 0; i--) {
- num += (s.charAt(i) - '0') * pos;
- pos *= 10;
- }
- return negative ? -num : num;
- }
- }
當(dāng)首個字符為負號‘-’的話,結(jié)果就返回負數(shù),并且把原來的字符串截取掉第一位。其他不變,這時候,當(dāng) a 為“-100”,b 為“50”的時候,a + b 的結(jié)果就是 -50。
我就問一句,造輪子的感覺是不是很爽?反正我已經(jīng)爽過了。
本文轉(zhuǎn)載自微信公眾號「沉默王二」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系沉默王二公眾號。