作者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
1F:推 AI3767:很久以前我也做过+和sb测试,有发现速度一样, 但,sb方便用於 04/01 23:12
2F:→ AI3767:在不同程式片段做接合. +比较适合所需字串一次性生成时 04/01 23:15
3F:推 cyclone350:我有点不懂,这在说用+号会被编译成append,那位啥最後 04/01 23:21
4F:→ cyclone350:的结论,会是需要明确指定用 StringBuilder 来增进效能 04/01 23:24
5F:→ cha122977:是不是使用场合有差?一次性字串用+没什麽差别, 04/01 23:26
6F:→ cyclone350:版主最後一句说没啥差别,原文说多50% !? 04/01 23:28
7F:→ cha122977:但是掺杂判断式而产生的字串 用StringBuilder比较好? 04/01 23:28
8F:→ cha122977:(是说推文间隔可不可以短一点 讨论起来好痛苦阿囧) 04/01 23:29
本来就不应该用推文的方式来讨论
这样看的人会很痛苦
另外,Java 版从来没有限制文章字数 or 行数
只在意是否言之有物
请见谅
9F:→ cyclone350:多50% 是愚人节的玩笑吗 ?? 04/01 23:31
10F:→ cha122977:话说曾在版上看过一篇跑很慢的 改用StringBuilder就解了 04/01 23:32
11F:→ cha122977:找到了 是这个~ #1Fc1oO9j 04/01 23:34
其实原文也不是那麽凄惨到完全无用
或着说,他给的 CatPlus 的 test case
其实就是要模拟
#1Fc1oO9j 的状态,也就是
while(FooCondition) {
str += str;
}
在这种情况下,虽然 + 的动作还是会改成用 append()
但是会重复宣告 StringBuilder
这才是真正造成效能瓶颈的地方
+ 号还是会变成 append() 的,这点可以肯定
只能说原 po(包含我)不够用功,不够龟毛
外加沾染了国内记者的习性,喜欢标题杀人,如此而已
(谜之声:还而已咧 [殴杀])
是说,要不是看了这篇
我还真的不知道原本的 + 号恶魔其实已经被处理掉了 XD
※ 编辑: PsMonkey 来自: 114.25.15.134 (04/01 23:46)
12F:推 AI3767:那篇在回圈内+=, 不是一次性加起来, 确实很高可能造成变慢 04/01 23:46
13F:→ cha122977:可以请教为何 str+=str; 会重复宣告吗?不太明白 04/01 23:56
14F:推 coolcomm:会在每次回圈产生新的instance 04/02 01:05