Tiger! Tiger!
福島さんに、
> J2SE5.0では、javacがうまくStringを、StringBuilderに変換してくれるそうです。
> http://www.javainthebox.net/laboratory/J2SE1.5/TinyTips/StringBuilder/StringBuilder.html
ということを教えてもらいました。
Javaで文字列を連結するときはStringBufferを使うというのが鉄則でしたが、常識は変わるものです。
もっとも、うまい話を素直に信じないのが技術屋です。
というわけで、調査してみました。
最初に用意したのは、こんなコード。
class Hoge {
public static void main(String[] arg) {
String s = "hoge";
s += "huga" + "muga";
s += "huuu";
System.out.println(s);
}
}
JDKのjavacでコンパイルして、javapで逆アセンブルすると、
Compiled from "Hoge.java"
class Hoge extends java.lang.Object{
Hoge();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2; //String hoge
2: astore_1
3: new #3; //class java/lang/StringBuilder
6: dup
7: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5; //Method java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6; //String hugamuga
16: invokevirtual #5; //Method java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7; //Method java/lang/StringBuilder.toString:
()Ljava/lang/String;
22: astore_1
23: new #3; //class java/lang/StringBuilder
26: dup
27: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
30: aload_1
31: invokevirtual #5; //Method java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: ldc #8; //String huuu
36: invokevirtual #5; //Method java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: invokevirtual #7; //Method java/lang/StringBuilder.toString:
()Ljava/lang/String;
42: astore_1
43: getstatic #9; //Field java/lang/System.out:Ljava/io/PrintStream;
46: aload_1
47: invokevirtual #10; //Method java/io/PrintStream.println:
(Ljava/lang/String;)V
50: return
}
と出ました。読みにくいので、適当にハンド逆コンパイルすると、
class Hoge {
public static void main(String[] arg) {
StringBuilder sb1 = new StringBuilder();
sb.append("hoge");
sb.append("hugamuga");
String s1 = sb1.toString();
StringBuilder sb2 = new StringBuilder();
sb.append(s1);
sb.append("huuu");
String s2 = sb2.toString();
System.out.println(s2);
}
}
となります。
StringBuilderを二つも作ってたりして、ちょっと頭の悪いコードです。
うまくやっている感じはしません。
次に用意したのはこんなの。
class Hoge {
public static void main(String[] arg) {
String s = "00000";
s += "aaaa";
s += "bbbb";
s += "cccc";
s += "dddd";
s += "eeee";
s += "ffffff";
System.out.println(s);
}
}
コンパイルして、逆アセンブルすると、StringBuilderとStringを6個ずつ生成しています。
お話になりません。
でも、
class Hoge {
public static void main(String[] arg) {
String s = "00000";
s += s + s + s + s + s + s + s;
System.out.println(s);
}
}
では、StringBuilderとStringは1個ずつしか生成されず、一つのStringBuilderに対してappend()が繰り返し呼ばれています。
どうも、Javaの一行に対してStringBuilderが一つ生成されるようです。
結論
・Javaのソースコード上、一行で連結を完結できる場合は+演算子で連結する (条件はこれであってる?)
・それ以外はStringBuilderで連結する
使い分けが面倒なら、常にStringBuilderを使います。
ただし、
・スレッド間で共有されるインスタンス変数やクラス変数は、従来通りStringBufferを使う
という条件は、常につきまといます。
- Category(s)
- 覚え書き
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/anaka/tiger-tiger/tbping
- メモリ増設記
- ¦
- Main
- ¦
- Genericsの罠
Re:Tiger! Tiger!
脱帽です。