開心一笑
【吃過晚飯在客廳看報紙,問老婆:你洗碗了嗎? 老婆嚴肅的說:老公,你應該這樣問,寶貝,我去幫你洗碗吧!然后我再說,老公,已經洗好了。這樣顯著多好…… 于是,老公:寶貝,我去幫你洗碗吧!老婆:恩,去吧。】
提出問題
項目中字符串操作應該注意的一些性能問題???
解決問題
以下來自《Java程序性能優化》這本書中的一點總結,以及自己的想法,每篇文章都很短,不太喜歡寫太多,一步一步慢慢學就可以了:
String類的基本實現:char數組,offset偏移量和String的count長度
對String優化主要表現在3個方面,同時也是String對象的3個特點:
- 不變性:String對象一旦生成,則不能再對它進行改變。
- 針對常量池的優化。
- 類的final定義。
例一:
@Test
public void testString(){
String boy = "boy";
String girl = "girl";
String girl2 = "girl";
String girl3 = new String("girl");
System.out.println(boy == girl);//false
System.out.println(girl == girl2);//true
System.out.println(girl == girl3);//false
System.out.println(girl == girl3.intern());//true
}
subString內存泄露問題
具體可以看高手文章:
在jdk6中,substring還是指向原來的字符串,可以用 new String(str.substring())避免內存泄露,
在jdk7中,沒有這個問題
字符串分割和查找
使用效率更高的StringTokenizer類分割字符
例二:
@Test
public void testString(){
String originalStr = null;
StringBuffer sb = new StringBuffer();
for(int i=0;i<10000;i++){
sb.append("ay");
sb.append(";");
}
originalStr = sb.toString();
long startTime = System.currentTimeMillis();
for(int i=0;i<10000;i++){
//在這里分割10000次
originalStr.split(";");
}
System.out.println(System.currentTimeMillis() - startTime);
}
結果花費:14920ms(我電腦比較 lan )
性能改造:
@Test
public void testString(){
String originalStr = null;
StringBuffer sb = new StringBuffer();
for(int i=0;i<10000;i++){
sb.append("ay");
sb.append(";");
}
originalStr = sb.toString();
long startTime = System.currentTimeMillis();
StringTokenizer tokenizer = new StringTokenizer(originalStr,";");
for(int i=0;i<10000;i++){
while (tokenizer.hasMoreTokens()){
tokenizer.nextToken();
}
}
System.out.println(System.currentTimeMillis() - startTime);
}
結果花費:8ms(我電腦比較 lan ) 這不是一個等級的啊!get起來
高效率的charAt()方法
charAt()效率比startsWith()或者endsWith效率高,對于判斷單個字符開頭的還可以,對于多個的話,我測試下,效率并沒有高很多。
例三:
@Test
public void testString3(){
String loveStr = "Love you!!!";
long startTime = System.currentTimeMillis();
//執行100萬次
for(int i=0;i<1000000;i++){
//判斷是否以L開頭
if(loveStr.charAt(0) == 'L'
){
}
}
System.out.println(System.currentTimeMillis() - startTime);
}
結果花費:20ms
@Test
public void testString4(){
String loveStr = "Love you!!!";
long startTime = System.currentTimeMillis();
//執行100萬次
for(int i=0;i<1000000;i++){
//判斷是否以L開頭
if(loveStr.startsWith("L")){
}
}
System.out.println(System.currentTimeMillis() - startTime);
}
結果花費:27ms
StringBuffer和StringBuilder
String對象是不可變對象,因此在需要對字符串進行修改操作時,如字符串連接,替換,String對象總是會生成新的對象,所以其性能相對較差。
例四:
String love = "999玫瑰" + "999電話" + "999晚安" + "999早安";
和
StringBuilder result = new StringBuilder();
result.append("999玫瑰");
result.append("999電話");
result.append("999晚安");
result.append("999早安");
因為java虛擬機對String拼接進行性能的優化。將多個連接操作的字符串,在編譯時合成一個單獨的長字符串。所以上面二者效率差不多
雖然二者的性能差不多,但是作者還是建議在代碼的實現中盡量地使用StringBuilder或者StringBuffer,來提升程序性能,而不是依靠編譯器對程序進行優化。
例五:
// 1
for(int i=0;i<10000;i++){
str = str + i;
}
//編譯器會把上面代碼編譯成以下代碼,但是每次會新建一個 StringBuilder對象,效率自然就低了
for(int i=0;i<10000;i++){
str = (new StringBuilder(String.valueOf(str))).append(i).toString();
}
// 2
for(int i=0;i<10000;i++){
result = result.concat(String.valueOf(i));
}
// 3
StringBuilder sb = new StringBuilder();
for(int i=0;i<10000;i++){
sb.append(i);
` }
上面的三個方法中效率(由低到高):
1 < 2 < 3
雖然java虛擬機會String的加法操作進行優化,但是編譯器還是不夠聰明。
StringBuffer和StringBuilder的選擇
StringBuffer和StringBuilder是一對孿生兄弟。
StringBuilder的效率 > StringBuffer的效率
StringBuilder是非線程安全的。StringBuffer是線程安全的。
可見一陰一陽之謂道,在任何地方都體現得淋漓盡致。
讀書感悟
來自張小嫻《面包樹上的女人》
想要忘記一段感情,方法永遠只有一個:時間和新歡。要是時間和新歡也不能讓你忘記一段感情,原因只有一個:時間不夠長,新歡不夠好。
我把青春投資在他身上,他成功了,也許會愛上另一個女人。他失敗了,我 一無所有。
愛情太不可靠了,只有事業才是一份耕耘一份收獲的,我想有自己的事業。不能把你留在身邊,不是你的過錯,而是我的失敗。在你曾經愛過我的那些短暫歲月里,我或許是世界上最幸福的人,只是那些日子已成過去,要留也留不住。我知道愛不可以乞求,如果我能夠為你做一件事,便是等待。
一個男人,泥足深陷地愛上一個不愛他的女人,注定要放棄自尊.
所有為愛而做的事,都不是壞事.
那時,我已經明白,作為一個女人,你最好很出色,或者很漂亮
其他
如果有帶給你一絲絲小快樂,就讓快樂繼續傳遞下去,歡迎轉載,點贊,頂,歡迎留下寶貴的意見,多謝支持!