作者PsMonkey (痞子軍團團長)
看板java
標題Re: [翻譯] 拆穿 Java StringBuilder 的謠言
時間Mon Apr 1 23:07:42 2013
本來想說 Java Code Geeks 的文章應該沒啥問題
所以翻完就算了,沒有仔細追究
BUT!
M Jwo 在 blog 上留了一個 comment
坦白說我看不是很懂,全文如下
本文大錯,僅有在 compiler 可以最佳化的有限場景才是,
通常是宣告的地方,不然放到method/loop裡面就知道了,
因為只有在 method/loop 才會對效能造成大影響,
少數幾個 String 根本不再效能需要調教的地方。
其實根本不用那麼麻煩,de-compiler 看一眼就知道
都是改用 StringBuffer/StringBuilder 了。
然後我才真的去翻了原作者提供的 javap 的結果
https://github.com/skuro/stringbuilder/blob/master/java7/CatPlus.class.txt
如果你跟我一樣沒辦法直接看懂 javap
那麼對應原始碼可能比較好懂
public class CatPlus extends ACat {
@Override
protected String cat(String base, String append){
String result = "const1" + base;
result = result + "const2";
return result + append;
}
}
也就是說,根本不是他說的那麼一回事情
在 Oracle JDK 7 之下,其實會用 append() 來代替 + 號
原作者 javap 的結果也是如此
要說效能慢的話,應該是因為他重複 assign 回 result
有 code 為證
我寫了一個單純的 class,在 JDK 6 下測試
public class CatPlus {
public String foo (String a, String b) {
return "const1" + a + "const2" + b;
}
}
javap 之後會得到
public class CatPlus extends java.lang.Object{
public CatPlus();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public java.lang.String foo(java.lang.String, java.lang.String);
Code:
0: new #2; //class java/lang/StringBuilder
3: dup
4: invokespecial #3;
//Method java/lang/StringBuilder."<init>":()V
7: ldc #4; //String const1
9: invokevirtual #5;
//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
12: aload_1
13: invokevirtual #5;
//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
16: ldc #6; //String const2
18: invokevirtual #5;
//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: aload_2
22: invokevirtual #5;
//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: invokevirtual #7;
//Method java/lang/StringBuilder.toString:()Ljava/lang/String;
28: areturn
}
所以,至少在 Oracle JDK 6 以後
字串用 + 號作連接跟用 StringBuilder 沒啥差別
========
只能說... 嗯... 愚人節快樂這樣? [核爆]
--
錢鍾書:
說出來的話
http://www.psmonkey.org
比不上不說出來的話
Java 版 cookcomic 版
只影射著說不出來的話
and more......
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 114.25.15.134
推 AI3767:很久以前我也做過+和sb測試,有發現速度一樣, 但,sb方便用於 04/01 23:12
→ AI3767:在不同程式片段做接合. +比較適合所需字串一次性生成時 04/01 23:15
推 cyclone350:我有點不懂,這在說用+號會被編譯成append,那位啥最後 04/01 23:21
→ cyclone350:的結論,會是需要明確指定用 StringBuilder 來增進效能 04/01 23:24
→ cha122977:是不是使用場合有差?一次性字串用+沒什麼差別, 04/01 23:26
→ cyclone350:版主最後一句說沒啥差別,原文說多50% !? 04/01 23:28
→ cha122977:但是摻雜判斷式而產生的字串 用StringBuilder比較好? 04/01 23:28
→ cha122977:(是說推文間隔可不可以短一點 討論起來好痛苦阿囧) 04/01 23:29
本來就不應該用推文的方式來討論
這樣看的人會很痛苦
另外,Java 版從來沒有限制文章字數 or 行數
只在意是否言之有物
請見諒
→ cyclone350:多50% 是愚人節的玩笑嗎 ?? 04/01 23:31
→ cha122977:話說曾在版上看過一篇跑很慢的 改用StringBuilder就解了 04/01 23:32
其實原文也不是那麼悽慘到完全無用
或著說,他給的 CatPlus 的 test case
其實就是要模擬
#1Fc1oO9j 的狀態,也就是
while(FooCondition) {
str += str;
}
在這種情況下,雖然 + 的動作還是會改成用 append()
但是會重複宣告 StringBuilder
這才是真正造成效能瓶頸的地方
+ 號還是會變成 append() 的,這點可以肯定
只能說原 po(包含我)不夠用功,不夠龜毛
外加沾染了國內記者的習性,喜歡標題殺人,如此而已
(謎之聲:還而已咧 [毆殺])
是說,要不是看了這篇
我還真的不知道原本的 + 號惡魔其實已經被處理掉了 XD
※ 編輯: PsMonkey 來自: 114.25.15.134 (04/01 23:46)
推 AI3767:那篇在迴圈內+=, 不是一次性加起來, 確實很高可能造成變慢 04/01 23:46
→ cha122977:可以請教為何 str+=str; 會重複宣告嗎?不太明白 04/01 23:56
推 coolcomm:會在每次迴圈產生新的instance 04/02 01:05