読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

「+」演算子での文字列連結は、コンパイラでStringBuilder#append()にされるよ!

Java

文字列をちょこっと連結したい時に、いちいちStringBuilderを使うのは面倒くさいですよねー。
というか、「+」で連結しても実はコンパイラがうまいこと最適化してくれるんじゃね?とふと思い立って調べて見ました。

結論:単純な連結なら、コンパイラがちゃんとStringBuilderにしてくれます。

↓のような1ステートメントに収まる単純な文字列連結であれば、コンパイラがちゃんとStringBuilderに変換してくれます

// リテラルの連結
String a1() {
    return "a" + "b";
}
String a2() {
    return "a" + "b" + "c";
}
String a3() {
    return "a" + 10;
}
String a4() {
    return 10 + "a";
}
String a5() {
    return "a" + 10 + "b";
}
String a6() {
    return "a" + true;
}
String a7() {
    return false + "a";
}
String a8() {
    return "a" + false + "b";
}
String a9() {
    return new Object() + "a";
}

// 引数、メソッドの評価結果
String b1( String x ) {
    return "a" + x;
}
String b2() {
    return "a" + String.valueOf(10);
}
String b3() {
    return "a" + b2();
}
String b4() {
    return a1() + b2();
}

javapの出力結果は以下。ちゃんとStringBuilder#appendを使うようにコンパイル時に変換されています。

java.lang.String a1();
  Code:
   0: ldc #2; //String ab
   2: areturn

java.lang.String a2();
  Code:
   0: ldc #3; //String abc
   2: areturn

java.lang.String a3();
  Code:
   0: ldc #4; //String a10
   2: areturn

java.lang.String a4();
  Code:
   0: ldc #5; //String 10a
   2: areturn

java.lang.String a5();
  Code:
   0: ldc #6; //String a10b
   2: areturn

java.lang.String a6();
  Code:
   0: ldc #7; //String atrue
   2: areturn

java.lang.String a7();
  Code:
   0: ldc #8; //String falsea
   2: areturn

java.lang.String a8();
  Code:
   0: ldc #9; //String afalseb
   2: areturn

java.lang.String a9();
  Code:
   0: new #10; //class java/lang/StringBuilder
   3: dup
   4: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   7: new #12; //class java/lang/Object
   10:  dup
   11:  invokespecial #1; //Method java/lang/Object."<init>":()V
   14:  invokevirtual #13; //Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
   17:  ldc #14; //String a
   19:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   22:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   25:  areturn

java.lang.String b1(java.lang.String);
  Code:
   0: new #10; //class java/lang/StringBuilder
   3: dup
   4: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   7: ldc #14; //String a
   9: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   12:  aload_1
   13:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   16:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   19:  areturn

java.lang.String b2();
  Code:
   0: new #10; //class java/lang/StringBuilder
   3: dup
   4: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   7: ldc #14; //String a
   9: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   12:  bipush  10
   14:  invokestatic  #17; //Method java/lang/String.valueOf:(I)Ljava/lang/String;
   17:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   20:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   23:  areturn

java.lang.String b3();
  Code:
   0: new #10; //class java/lang/StringBuilder
   3: dup
   4: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   7: ldc #14; //String a
   9: invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   12:  aload_0
   13:  invokevirtual #18; //Method b2:()Ljava/lang/String;
   16:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   22:  areturn

java.lang.String b4();
  Code:
   0: new #10; //class java/lang/StringBuilder
   3: dup
   4: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   7: aload_0
   8: invokevirtual #19; //Method a1:()Ljava/lang/String;
   11:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   14:  aload_0
   15:  invokevirtual #18; //Method b2:()Ljava/lang/String;
   18:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   21:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   24:  areturn
  • メソッドの呼び出し結果や引数と連結する場合もOK。
  • リテラル同士の連結なら、連結された状態でクラスに埋め込まれるため、StringBuilderさえ登場しません。

最適化されないパターン

うまく最適化されなかったパターンは以下。試した範囲では、連結を複数ステートメントに別けて行なうとダメみたいですね。複数のStringBuilderに分割されてしまっています。

// 複数のステートメントに別けて連結
String c1() {
    String str = "a";
    str = str + "b"; 
    str = str + "c";
    str = str + "d"; 
    return str;
}
String c2() {
    String str = "a";
    str += "b";
    str += "c";
    str += "d";
    return str;
}

javapの出力結果です。

java.lang.String c1();
  Code:
   0: ldc #14; //String a
   2: astore_1
   3: new #10; //class java/lang/StringBuilder
   6: dup
   7: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   10:  aload_1
   11:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   14:  ldc #20; //String b
   16:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   22:  astore_1
   23:  new #10; //class java/lang/StringBuilder
   26:  dup
   27:  invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   30:  aload_1
   31:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   34:  ldc #21; //String c
   36:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   39:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   42:  astore_1
   43:  new #10; //class java/lang/StringBuilder
   46:  dup
   47:  invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   50:  aload_1
   51:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   54:  ldc #22; //String d
   56:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   59:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   62:  astore_1
   63:  aload_1
   64:  areturn
   
java.lang.String c2();
  Code:
   0: ldc #14; //String a
   2: astore_1
   3: new #10; //class java/lang/StringBuilder
   6: dup
   7: invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   10:  aload_1
   11:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   14:  ldc #20; //String b
   16:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   22:  astore_1
   23:  new #10; //class java/lang/StringBuilder
   26:  dup
   27:  invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   30:  aload_1
   31:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   34:  ldc #21; //String c
   36:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   39:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   42:  astore_1
   43:  new #10; //class java/lang/StringBuilder
   46:  dup
   47:  invokespecial #11; //Method java/lang/StringBuilder."<init>":()V
   50:  aload_1
   51:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   54:  ldc #22; //String d
   56:  invokevirtual #15; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   59:  invokevirtual #16; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   62:  astore_1
   63:  aload_1
   64:  areturn

まとめ

  • 文字列をちょこっと連結するだけなら、「+」演算子でさくっと繋いでOK。コンパイラがStringBuilderに変換してくれます。
  • 長めの文字列を作る時は
String str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
str += "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
str += "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
str += "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
str += "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
str += "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
str += "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
str += "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

ではなく、

String str = 
      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

と書くとちょっと早い。(ただし、よほどクリティカルな部分でない限り無視していいレベルと思われますが・・・。)


これで内なる原理主義者との葛藤から、少しは解放されますね!