Re: [翻譯] 拆穿 Java StringBuilder 的謠言
(我知道這篇有點久,我一直想回可是一直都忘了)
第一眼看到裡面的 test code, 就覺得不太對勁。
我想是原文作者對 "+ 會轉成 StringBuffer/StringBuilder"
這句話的意思有誤解吧。
在書上(忘了哪一本,印象中很多書都有提到)看到的是, String 的 +
是會轉化為 StringBuffer,但這是指 compilation 的過程,當 compiler
看到
aString + x + y + z;
會把它替換為
new StringBuffer(aString).append(x).append(y).append(z).toString();
而已。(JDK5+ 則用 StringBuilder)
(我相信這是在 JLS 有規範的可是我沒去找 :P )
原文中做的是
result = a + b;
result = result + c;
這類的動作
旨望 JIT 做 optimization 還有可能,可是 compiler 大概
不會做什麼特別動作:
result = new StringBuffer(a).append(b).toString();
result = new StringBuffer(result).append(c).toString();
想當然爾,這樣的 code 和
result = new StringBuffer(a).append(b).append(c).toString();
相比一定比較慢。
問題是,Compiler 不會跨 expression 做這類 optimization 很
正常呀。
要是原本做的就是 result = a + b + c;
我猜結果應該沒什麼大分別。
然後大概有人會問,反正都是替換成 StringBuffer/StringBuilder
那麼倒不如不要用 +, 一直都用 StringBuilder 不就保險了嗎?
並不是!
我想到的就有三大原因:
1) 很多情況下 + 比較好讀,尤其一句 expression 裡串連一堆 string,
用 StringBuilder 累贅得不得了
2) 由 JDK5 開始,+ 會用 StringBuilder. 要是有一些 JDK5 以前寫的
code 在沒有修改下 recompile, 用 + 的會因為由 StringBuffer 轉
成 StringBuilder 而有效能增長,但手工 StringBuffer 就沒了
3) 最重要的原因,有時 + 會跑很比手工 StringBuilder 快。
問題就出在 String literal 身上:
String result = "some " + "string " + "literals";
vs
String result = new StringBuilder("some ")
.append("string ")
.append("literals")
.toString();
第一種情況下,Compiler 是會把 string literal 連成一個literal,
而又因為是直接 assign, 又省了 string builder, 變成:
String result = "some string literals";
另外有人把用 StringBuilder 類比為 premature optimization
或 over-design,而主張只用 +/+= 。我實在不能苟同。與其期
望 JIT 或許可以幫忙 optimize (可是本身又不清楚 JIT 可以
達到的範圍),倒不如在不影響程式可讀性的情況下選擇恰當的
string 串接手段。
String sql = "select balblabla from table where a=b";
if (c) {
sql += "and c = d";
}
if (e) {
sql += "and e = f";
};
相比
StringBuilder sql
= new StringBuilder("select balblabla from table where a=b");
if (c) {
sql.append("and c = d");
}
if (e) {
sql.append("and e = f");
};
後者真的有比較難讀嗎?
可是前者卻是當 c 與 e 都出現的時候,白白浪費了兩個 StringBuilder。
當然只有一兩個看起來沒啥分別,可是當成了習慣或 convention,十個二十
個 criteria 也自然會用一樣的方法來寫。這還能接受嗎?
個人簡單的規則:當你的 string concatenation 只是在一句
expression 內,請用 +, 否則請用 StringBuilder.
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 223.19.42.175
※ 編輯: adrianshum 來自: 223.19.42.175 (04/19 09:46)
→
04/19 10:36, , 1F
04/19 10:36, 1F
→
04/19 21:22, , 2F
04/19 21:22, 2F
→
04/19 21:22, , 3F
04/19 21:22, 3F
討論串 (同標題文章)
完整討論串 (本文為第 8 之 8 篇):