開心一笑
【一個本科男找了一個女博士。新春佳節(jié),本科男紿女博士發(fā)了一個520元的紅包,附言:我愛你。稍后,女博士給本科男發(fā)了一個5.20元的紅包,并附言:我愛你多一點!本科男感嘆道:有文化,太可怕,少花錢,會說話!】
提出問題
項目中如何優(yōu)雅使用字符串 ???

解決問題
初始化字符串的兩種選擇比較
例:
//第一種初始化字符串方式
String str = "ay";
String str2 = "ay";
System.out.println(str == str2);
//第二種初始化字符串方式
String newStr = new String("ay");
System.out.println(str == newStr);
//打印結(jié)果
true
false
通過上面實例,我們可以看到:第一種初始化字符串的方法,事實上是把字符串放到常量池里面。當(dāng)創(chuàng)建 str2 字符串的時候,它會到常量池尋找,找不到,就創(chuàng)建之。找到了,就把對象引用傳給 str2 。因為 String 類是 final 的且 String 的所有方法有返回的 String 字符串的,都會重新新建一個新的 String 對象。所有不會有線程安全問題。綜上所述,建議大家在以后開發(fā)過程中,使用第一種方式,優(yōu)雅的創(chuàng)建字符串。
字符串常量equals時候?qū)⒆址A繉懺谇懊?/h4>
判斷字符相等是最常見的情景,例如:
@Test
public void test(){
String str = "ay";
if(str.equals("ay")){
System.out.println("不推薦寫法");
}
String str2 = null;
if("ay".equals(str2)){
System.out.println("推薦寫法");
}
if(str2.equals("ay")){
System.out.println("出現(xiàn) NullPointerException 異常");
}
}
如果我們把字符常量 ay 寫在 equals 前面,即使兩個字符串不相等,也不會產(chǎn)生空指針異常。可以達(dá)到優(yōu)雅的判斷是否相等。
for循環(huán)中不寫字符串拼接
我們知道,for循環(huán)中,除了不要做數(shù)據(jù)庫連接,查詢數(shù)據(jù)庫和處理異常外。在循環(huán)次數(shù)比較多的for循環(huán)中,我們也不要利用 + 號去拼接字符串。具體例子如下:
程序清單 1-1
@Test
public void test(){
String str = "ay";
for(int i=0;i<Integer.MAX_VALUE;i++){
str = str + i;
}
}
這個問題也是老生常談的了。具體解決方法如下:
- 根據(jù)具體的業(yè)務(wù)場景,使用 StringBuffer(線程安全)或者 StringBuilder(非線程安全)
- 使用數(shù)組
程序清單 1-1
@Test
public void test(){
//第一種解決方法
StringBuilder stringBuilder = new StringBuilder(Integer.MAX_VALUE);
//第二種解決方法
String[] strArray = new String[Integer.MAX_VALUE + 1];
stringBuilder.append("ay");
strArray[0] = "ay";
for(int i=0;i<Integer.MAX_VALUE + 1;i++){
stringBuilder.append("al");
strArray[i + 1] = "al";
}
System.out.println(stringBuilder.toString());
System.out.println(ArrayUtils.toString(strArray));
}
不過,java在長久的發(fā)展歷程中,編譯器會對字符串拼接進(jìn)行優(yōu)化。但是在多種可選的方案下,我建議大家使用最優(yōu)雅的方式去實現(xiàn)字符串拼接,就是 StringBuffer(線程安全)或者 StringBuilder(非線程安全)
設(shè)置容量參數(shù)提高系統(tǒng)性能
對于 StringBuffer(線程安全)或者 StringBuilder(非線程安全),都有相應(yīng)的構(gòu)造方法:
程序清單 1-1
public StringBuilder(int capacity) {
super(capacity);
}
如果我們可以事先知道需要拼接的字符串長度,設(shè)置容量參數(shù),防止 StringBuffer 在源碼內(nèi)部進(jìn)行一系列復(fù)雜的內(nèi)存復(fù)制操作,影響性能。
如上面的
StringBuilder stringBuilder = new StringBuilder(Integer.MAX_VALUE);
實現(xiàn)高性能的字符串分割
實現(xiàn)字符串的分割的方法有很多種,常用的是 split ,StringTokenizer ,indexOf 和 substring 的配合,以及一些開源工具類,如:StringUtils。它們各有優(yōu)缺。
@Test
public void test(){
//數(shù)據(jù)初始化
StringBuffer sb = new StringBuffer();
for(int i=0;i<10000;i++){
sb.append(i).append(";");
}
String originStr = sb.toString();
//第一種分隔字符方法
long startTime = System.nanoTime();
String[] splitArray = originStr.split(";");
for(int i=0,len = splitArray.length;i<len;i++){
String temp = splitArray[i];
}
long endTime = System.nanoTime();
System.out.println("the cost of split is :" + (endTime - startTime));
//第二種分隔字符方法
System.out.println("--------------------------------------------");
originStr = sb.toString();
startTime = System.nanoTime();
StringTokenizer st = new StringTokenizer(originStr,";");
while(st.hasMoreTokens()){
st.nextToken();
}
endTime = System.nanoTime();
System.out.println("the cost of stringTokenizer is :" + (endTime - startTime));
//第三種分隔字符的方法
System.out.println("--------------------------------------------");
originStr = sb.toString();
startTime = System.nanoTime();
while (true){
int index = originStr.indexOf(";");
if(index < 0) break;
String origin = originStr.substring(0,index);
originStr = originStr.substring(index + 1);
}
endTime = System.nanoTime();
System.out.println("the cost of indexOf is :" + (endTime - startTime));
//第四種分隔字符的方法
System.out.println("--------------------------------------------");
originStr = sb.toString();
startTime = System.nanoTime();
String[] utilSplit = StringUtils.split(originStr,';');
for(int i=0,len = utilSplit.length;i<len;i++){
String temp = utilSplit[i];
}
endTime = System.nanoTime();
System.out.println("the cost of StringUtils.split is :" + (endTime - startTime));
}
運行結(jié)果:
the cost of split is :35710479
--------------------------------------------
the cost of stringTokenizer is :11992643
--------------------------------------------
the cost of indexOf is :323050471
--------------------------------------------
the cost of StringUtils.split is :59026333
從上面例子可以看出,字符分割的性能,由高到低的排序為:StringTokenizer > split ,StringUtils.split > indexOf 。有些書籍寫著 indexOf 的性能是最高的,但是按照我的測試,index的性能是最差的。但是事物都有兩面性,從上面的例子也可以看出,雖然 StringTokenizer 的性能高,但是代碼量多,可讀性差,而 split 代碼相對就整潔多了。
讀書感悟
來自《我腦袋里的怪東西》
- 讓一千萬人聚集在伊斯坦布爾的東西是生計、利益、帳單,但支撐這茫茫人海的只有一樣?xùn)|西,那就是愛!
- 身處城市熙熙攘攘的人群中,也可能感到孤獨,但是讓城市成為城市的東西,也恰恰是這種能夠在人群中隱藏自己頭腦里的怪念頭的可能。
- 有時覺得,自己正在經(jīng)歷人生中最幸福的歲月,但只把這種感覺存放在腦海的一個角落里。因為擔(dān)心,如果總想著自己幸福,就可能失去它。
經(jīng)典故事
【一只烏鴉坐在樹上,整天無所事事。一只小兔子看見烏鴉,就問:“我能象你一樣整天坐在那里,什么事也不干嗎?”烏鴉答道:“當(dāng)然啦,為什么不呢?”于是,兔子便坐在樹下,開始休息。突然,一只狐貍出現(xiàn)了。狐貍跳向兔子……并把它給吃了。這個故事的寓意是……要想坐在那里什么也不干,你必須坐(做)得非常非常高】
大神文章
【1】《Agile Java》
【2】《Java程序性能優(yōu)化 讓你的Java程序更快、更穩(wěn)定》
【3】《Thinking in Java (Java編程思想)》
【4】《編寫高質(zhì)量代碼:改善Java程序的151個建議》
其他
如果有帶給你一絲絲小快樂,就讓快樂繼續(xù)傳遞下去,歡迎點贊、頂、歡迎留下寶貴的意見、多謝支持!