[Java]文字列連結で、+演算子 or StringBuilder どちらを使うべき?

 

 

こんにちは。ナガオカ(@boot_kt)です。

 

Javaの文字列の結合は、演算子が良いのか、StringBuilder(or StringBuffer)が良いのか、これもよく聞く問題です

先に結論言っちゃうと、コンパイル時に最適化されるので、演算子を積極的に使うと良いです
むしろ、StringBuilderにしてると最適化が効かず効率が悪いこともあります

とは言え、全ての場面で演算子を使えばいいかと言うとそうでもないんですよねぇ~
StringBuilderを使う方が良い場面もあります

この記事では、javap.exeを使って、文字連結時に使う演算子とStringBuilderの使い分け方の根本的な考え方を示します
 

ちょっと記事の文量が多いように見えますが、読むべき量は意外と少ないので、良かったら最後まで見てあげてください

 

StringBuilderStringBufferについて
StringBuilderStringBufferも使い方は同じですしそれほど大きな違いは無いため、本記事ではStringBuilderのみを取り上げます

ちなみに、StringBuilderStringBufferとの違いは

  • StringBuilder
    スレッド処理なし
    処理早い
  • StringBuffer
    スレッド処理あり
    処理遅い
  • 現実的にはスレッド云々は別途対応して、StringBuilderを使えばいいのかなと思います
    StringBufferを使うメリットがあまり無い?

この記事のザックリした内容
◆対象読者

  • Javaの文字列の結合は演算子さえ使っておけばいいと思っている人
  • Javaの文字列の結合はStringBuilderクラスさえ使っておけばいいと思っている人
  • Javaの文字列の結合の事なんて考えたこと無かった人
  • Javaの知識必要
  • JDKをインストールしている

 

◆解決できるかも知れないお悩み

  • Javaの文字列結合において、演算子とStringBuilderクラスの使い分け方が理解できます

 

◆どうやって解決するか

  • javap.exeを使って、ソースコードの展開方法(バイトコード)を見ます

 

 

 

 

まずは結論! 演算子とStringBuilderクラスとの使い分け方

  1. 基本的には演算子を使えばいいです
  2. 但し、1行で全部の文字列を連結する場合のみ
  3. 何行かに分けて連結する場合は、StringBuilderクラスを使ってね
  4. forとかwhileの中ではStringBuilderクラスを使う方が良いでしょう
  5. どっちを使えばいいか分からない場合は、javap.exeで確認せよ!

 

javapを使ってみよう

javaファイルをコンパイルすると、バイトコードというものに展開されます
バイトコードに展開される内容はソースコードと全く同じというわけではなく最適化されることがありますし使用している命令が変わることもあります

Javaの実行環境であるJVMはそのバイトコードを読み取って実行してくれます
ですので、実際にどのようなコードで動くのかはバイトコードを見るのが良いのです
 

で、そのバイトコードがclassファイルです
※classファイルはバイトコード以外の情報も持ってるよ

javapを使えばclassファイルに入っているバイトコードが見られます

 

まずはjavapの存在を確認

JDKをインストールした時のディレクトリのbinフォルダにjavapはいます

僕の環境だとここ↓

  • C:\Program Files\Java\jdk1.8.0_72\bin\javap.exe

WindowsでもMacでもPATHを通していると思うので、以下のコマンドを打ってみてください

> javap -help

↓こんな感じで何か表示されればOKです

>javap -help
使用方法: javap  
使用可能なオプションには次のものがあります:
  -help  --help  -?        この使用方法のメッセージを出力する
  -version                 バージョン情報
  -v  -verbose             追加情報を出力する
  -l                       行番号とローカル変数表を出力する
  -public                  publicクラスおよびメンバーのみを表示する
  -protected               protected/publicクラスおよびメンバーのみを表示する
  -package                 package/protected/publicクラスおよび
                           メンバーのみを表示する(デフォルト)
  -p  -private             すべてのクラスとメンバーを表示する
  -c                       コードを逆アセンブルする
  -s                       内部タイプ署名を出力する
  -sysinfo                 処理しているクラスのシステム情報(パス、サイズ、日付、MD5ハッシュ)
                           を表示する
  -constants               final定数を表示する
  -classpath         ユーザー・クラス・ファイルを検索する場所を指定する
  -cp                ユーザー・クラス・ファイルを検索する場所を指定する
  -bootclasspath     ブートストラップ・クラス・ファイルの場所をオーバーライドする

以下のソースコードをコンパイルします

このソースコードをコンパイルしてclassファイルを作ってちょーーーだい!

Main.java
Main.javaは別にコンパイルしなくてもいいですよ
動かしたいのであればコンパイルすればいいですが、SamplePlus.javaとSampleBuilder.javaさえコンパイルしてもらえればOKです
public class Main {
    public static void main(String argv[]) {
        SamplePlus sp = new SamplePlus();

        System.out.println( "Test11 : " + sp.Test11() );
        System.out.println( "Test12 : " + sp.Test12() );
        System.out.println( "Test13 : " + sp.Test13() );
        System.out.println( "Test14 : " + sp.Test14() );

        System.out.println( "Test21 : " + sp.Test21() );
        System.out.println( "Test22 : " + sp.Test22() );
        System.out.println( "Test23 : " + sp.Test23() );
        System.out.println( "Test24 : " + sp.Test24() );
        System.out.println( "Test25 : " + sp.Test25() );
        System.out.println( "Test26 : " + sp.Test26() );


        SampleBuilder sb = new SampleBuilder();

        System.out.println( "Test11 : " + sb.Test11() );
        System.out.println( "Test12 : " + sb.Test12() );

        System.out.println( "Test22 : " + sb.Test22() );
        System.out.println( "Test24 : " + sb.Test24() );
        System.out.println( "Test26 : " + sb.Test26() );
    }
}
public class SamplePlus {
    //===========================================================
    // ノーマル系
    //===========================================================
    //***********************************************************
    // 大分類:1行で連結
    // 中分類:String変数使用
    // 小分類:---
    //***********************************************************
    public static String Test11() {
        String  hoge = "aiueo";
        String  fuga = "kakikukeko";
        String  piyo = "sasisuseso";
        String  gabo;

        gabo = hoge + fuga + piyo;

        return gabo;
    }
    //***********************************************************
    // 大分類:1行で連結
    // 中分類:文字列使用
    // 小分類:---
    //***********************************************************
    public static String Test12() {
        String  gabo;

        gabo = "aiueo" + "kakikukeko" + "sasisuseso";

        return gabo;
    }


    //***********************************************************
    // 大分類:複数行で連結
    // 中分類:String変数使用
    // 小分類:---
    //***********************************************************
    public static String Test13() {
        String  hoge = "aiueo";
        String  fuga = "kakikukeko";
        String  piyo = "sasisuseso";
        String  gabo;

        gabo = "";
        gabo += hoge;
        gabo += fuga;
        gabo += piyo;

        return gabo;
    }

    //***********************************************************
    // 大分類:複数行で連結
    // 中分類:文字列使用
    // 小分類:---
    //***********************************************************
    public static String Test14() {
        String  hoge = "aiueo";
        String  fuga = "kakikukeko";
        String  piyo = "sasisuseso";
        String  gabo;

        gabo = "";
        gabo += "aiueo";
        gabo += "kakikukeko";
        gabo += "sasisuseso";

        return gabo;
    }

    //***********************************************************
    // 大分類:1行で連結
    // 中分類:String変数と文字列の混合使用
    // 小分類:---
    //***********************************************************
    public static String Test15() {
        String  hoge = "aiueo";
        String  piyo = "sasisuseso";
        String  gabo;

        gabo = hoge + "kakikukeko" + piyo + "tatituteto";

        return gabo;
    }

    //===========================================================
    // ループ系
    //===========================================================
    //***********************************************************
    // 大分類:ループ使用
    // 中分類:String変数使用
    // 小分類:ループの【外】でString変数定義
    //       :代入系
    //***********************************************************
    public static String Test21() {
        String  hoge = "aiueo";
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            gabo = hoge;
        }

        return gabo;
    }
    //***********************************************************
    // 大分類:ループ使用
    // 中分類:String変数使用
    // 小分類:ループの【外】でString変数定義
    //       :足していく系
    //***********************************************************
    public static String Test22() {
        String  hoge = "aiueo";
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            gabo += hoge;
        }

        return gabo;
    }

    //***********************************************************
    // 大分類:ループ使用
    // 中分類:String変数使用
    // 小分類:ループの【中】でString変数定義
    //       :代入系
    //***********************************************************
    public static String Test23() {
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            String  hoge = "aiueo";
            gabo = hoge;
        }

        return gabo;
    }


    //***********************************************************
    // 大分類:ループ使用
    // 中分類:String変数使用
    // 小分類:ループの【中】でString変数定義
    //       :足していく系
    //***********************************************************
    public static String Test24() {
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            String  hoge = "aiueo";
            gabo += hoge;
        }

        return gabo;
    }

    //***********************************************************
    // 大分類:ループ使用
    // 中分類:文字列使用
    // 小分類:---
    //       :代入系
    //***********************************************************
    public static String Test25() {
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            gabo = "aiueo";
        }

        return gabo;
    }

    //***********************************************************
    // 大分類:ループ使用
    // 中分類:文字列使用
    // 小分類:---
    //       :足していく系
    //***********************************************************
    public static String Test26() {
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            gabo += "aiueo";
        }

        return gabo;
    }
}
public class SampleBuilder {
    //===========================================================
    // ノーマル系
    //===========================================================
    //***********************************************************
    // 大分類:1行で連結
    // 中分類:String変数使用
    // 小分類:---
    //***********************************************************
    public static String Test11() {
        String  hoge = "aiueo";
        String  fuga = "kakikukeko";
        String  piyo = "sasisuseso";
        StringBuilder  gabo = new StringBuilder();

        gabo.append(hoge);
        gabo.append(fuga);
        gabo.append(piyo);

        return gabo.toString();
    }
    //***********************************************************
    // 大分類:1行で連結
    // 中分類:文字列使用
    // 小分類:---
    //***********************************************************
    public static String Test12() {
        StringBuilder  gabo = new StringBuilder();

        gabo.append("aiueo");
        gabo.append("kakikukeko");
        gabo.append("sasisuseso");

        return gabo.toString();
    }


//     //***********************************************************
//     // 大分類:複数行で連結
//     // 中分類:String変数使用
//     // 小分類:---
//     //***********************************************************
//     public static String Test13() {
//
//     }

//     //***********************************************************
//     // 大分類:複数行で連結
//     // 中分類:文字列使用
//     // 小分類:---
//     //***********************************************************
//     public static String Test14() {
//
//     }

    //***********************************************************
    // 大分類:1行で連結
    // 中分類:String変数と文字列の混合使用
    // 小分類:---
    //***********************************************************
    public static String Test15() {
        String  hoge = "aiueo";
        String  piyo = "sasisuseso";
        StringBuilder  gabo = new StringBuilder();

        gabo.append(hoge);
        gabo.append("kakikukeko");
        gabo.append(piyo);
        gabo.append("tatituteto");

        return gabo.toString();
    }

    //===========================================================
    // ループ系
    //===========================================================
//     //***********************************************************
//     // 大分類:ループ使用
//     // 中分類:String変数使用
//     // 小分類:ループの【外】でString変数定義
//     //       :代入系
//     //***********************************************************
//     public static String Test21() {
//
//     }
    //***********************************************************
    // 大分類:ループ使用
    // 中分類:String変数使用
    // 小分類:ループの【外】でString変数定義
    //       :足していく系
    //***********************************************************
    public static String Test22() {
        String  hoge = "aiueo";
        StringBuilder  gabo = new StringBuilder();

        for(int i=0; i < 100; i++) {
            gabo.append(hoge);
        }

        return gabo.toString();
    }

//     //***********************************************************
//     // 大分類:ループ使用
//     // 中分類:String変数使用
//     // 小分類:ループの【中】でString変数定義
//     //       :代入系
//     //***********************************************************
//     public static String Test23() {
//     }


    //***********************************************************
    // 大分類:ループ使用
    // 中分類:String変数使用
    // 小分類:ループの【中】でString変数定義
    //       :足していく系
    //***********************************************************
    public static String Test24() {
        StringBuilder  gabo = new StringBuilder();

        for(int i=0; i < 100; i++) {
            String  hoge = "aiueo";
            gabo.append(hoge);
        }

        return gabo.toString();
    }

//     //***********************************************************
//     // 大分類:ループ使用
//     // 中分類:文字列使用
//     // 小分類:---
//     //       :代入系
//     //***********************************************************
//     public static String Test25() {
//
//     }

    //***********************************************************
    // 大分類:ループ使用
    // 中分類:文字列使用
    // 小分類:---
    //       :足していく系
    //***********************************************************
    public static String Test26() {
        StringBuilder  gabo = new StringBuilder();

        for(int i=0; i < 100; i++) {
            gabo.append("aiueo");
        }

        return gabo.toString();
    }
}

 

javapでclassファイルを読み込みます

> javap -c SamplePlus.class
> javap -c SampleBuilder.class

テキストファイルに出力したければリダイレクトしてください

> javap -c SamplePlus.class > SamplePlus_javap.txt
> javap -c SampleBuilder.class > SampleBuilder_javap.txt

こんなデータが出力されます
↓これがバイトコードです

Compiled from "SamplePlus.java"
public class SamplePlus {
  public SamplePlus();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public static java.lang.String Test11();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #3                  // String kakikukeko
       5: astore_1
       6: ldc           #4                  // String sasisuseso
       8: astore_2
       9: new           #5                  // class java/lang/StringBuilder
      12: dup
      13: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      16: aload_0
      17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      20: aload_1
      21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: aload_2
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: astore_3
      32: aload_3
      33: areturn

  public static java.lang.String Test12();
    Code:
       0: ldc           #9                  // String aiueokakikukekosasisuseso
       2: astore_0
       3: aload_0
       4: areturn

  public static java.lang.String Test13();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #3                  // String kakikukeko
       5: astore_1
       6: ldc           #4                  // String sasisuseso
       8: astore_2
       9: ldc           #10                 // String
      11: astore_3
      12: new           #5                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      19: aload_3
      20: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: aload_0
      24: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_3
      31: new           #5                  // class java/lang/StringBuilder
      34: dup
      35: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      38: aload_3
      39: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      42: aload_1
      43: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      46: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      49: astore_3
      50: new           #5                  // class java/lang/StringBuilder
      53: dup
      54: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      57: aload_3
      58: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      61: aload_2
      62: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      65: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      68: astore_3
      69: aload_3
      70: areturn

  public static java.lang.String Test14();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #3                  // String kakikukeko
       5: astore_1
       6: ldc           #4                  // String sasisuseso
       8: astore_2
       9: ldc           #10                 // String
      11: astore_3
      12: new           #5                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      19: aload_3
      20: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: ldc           #2                  // String aiueo
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: astore_3
      32: new           #5                  // class java/lang/StringBuilder
      35: dup
      36: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      39: aload_3
      40: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      43: ldc           #3                  // String kakikukeko
      45: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      48: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      51: astore_3
      52: new           #5                  // class java/lang/StringBuilder
      55: dup
      56: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      59: aload_3
      60: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      63: ldc           #4                  // String sasisuseso
      65: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      68: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      71: astore_3
      72: aload_3
      73: areturn

  public static java.lang.String Test15();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #4                  // String sasisuseso
       5: astore_1
       6: new           #5                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      13: aload_0
      14: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      17: ldc           #3                  // String kakikukeko
      19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: aload_1
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: ldc           #11                 // String tatituteto
      28: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      31: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      34: astore_2
      35: aload_2
      36: areturn

  public static java.lang.String Test21();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #10                 // String
       5: astore_1
       6: iconst_0
       7: istore_2
       8: iload_2
       9: bipush        100
      11: if_icmpge     22
      14: aload_0
      15: astore_1
      16: iinc          2, 1
      19: goto          8
      22: aload_1
      23: areturn

  public static java.lang.String Test22();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #10                 // String
       5: astore_1
       6: iconst_0
       7: istore_2
       8: iload_2
       9: bipush        100
      11: if_icmpge     39
      14: new           #5                  // class java/lang/StringBuilder
      17: dup
      18: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      21: aload_1
      22: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      25: aload_0
      26: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      29: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      32: astore_1
      33: iinc          2, 1
      36: goto          8
      39: aload_1
      40: areturn

  public static java.lang.String Test23();
    Code:
       0: ldc           #10                 // String
       2: astore_0
       3: iconst_0
       4: istore_1
       5: iload_1
       6: bipush        100
       8: if_icmpge     22
      11: ldc           #2                  // String aiueo
      13: astore_2
      14: aload_2
      15: astore_0
      16: iinc          1, 1
      19: goto          5
      22: aload_0
      23: areturn

  public static java.lang.String Test24();
    Code:
       0: ldc           #10                 // String
       2: astore_0
       3: iconst_0
       4: istore_1
       5: iload_1
       6: bipush        100
       8: if_icmpge     39
      11: ldc           #2                  // String aiueo
      13: astore_2
      14: new           #5                  // class java/lang/StringBuilder
      17: dup
      18: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      21: aload_0
      22: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      25: aload_2
      26: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      29: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      32: astore_0
      33: iinc          1, 1
      36: goto          5
      39: aload_0
      40: areturn

  public static java.lang.String Test25();
    Code:
       0: ldc           #10                 // String
       2: astore_0
       3: iconst_0
       4: istore_1
       5: iload_1
       6: bipush        100
       8: if_icmpge     20
      11: ldc           #2                  // String aiueo
      13: astore_0
      14: iinc          1, 1
      17: goto          5
      20: aload_0
      21: areturn

  public static java.lang.String Test26();
    Code:
       0: ldc           #10                 // String
       2: astore_0
       3: iconst_0
       4: istore_1
       5: iload_1
       6: bipush        100
       8: if_icmpge     37
      11: new           #5                  // class java/lang/StringBuilder
      14: dup
      15: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      18: aload_0
      19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: ldc           #2                  // String aiueo
      24: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_0
      31: iinc          1, 1
      34: goto          5
      37: aload_0
      38: areturn
}
Compiled from "SampleBuilder.java"
public class SampleBuilder {
  public SampleBuilder();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return

  public static java.lang.String Test11();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #3                  // String kakikukeko
       5: astore_1
       6: ldc           #4                  // String sasisuseso
       8: astore_2
       9: new           #5                  // class java/lang/StringBuilder
      12: dup
      13: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      16: astore_3
      17: aload_3
      18: aload_0
      19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: pop
      23: aload_3
      24: aload_1
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: pop
      29: aload_3
      30: aload_2
      31: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      34: pop
      35: aload_3
      36: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      39: areturn

  public static java.lang.String Test12();
    Code:
       0: new           #5                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #6                  // Method java/lang/StringBuilder."":()V
       7: astore_0
       8: aload_0
       9: ldc           #2                  // String aiueo
      11: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: pop
      15: aload_0
      16: ldc           #3                  // String kakikukeko
      18: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: pop
      22: aload_0
      23: ldc           #4                  // String sasisuseso
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: pop
      29: aload_0
      30: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      33: areturn

  public static java.lang.String Test15();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #4                  // String sasisuseso
       5: astore_1
       6: new           #5                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      13: astore_2
      14: aload_2
      15: aload_0
      16: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: pop
      20: aload_2
      21: ldc           #3                  // String kakikukeko
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: pop
      27: aload_2
      28: aload_1
      29: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      32: pop
      33: aload_2
      34: ldc           #9                  // String tatituteto
      36: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      39: pop
      40: aload_2
      41: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      44: areturn

  public static java.lang.String Test22();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: new           #5                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      10: astore_1
      11: iconst_0
      12: istore_2
      13: iload_2
      14: bipush        100
      16: if_icmpge     31
      19: aload_1
      20: aload_0
      21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: pop
      25: iinc          2, 1
      28: goto          13
      31: aload_1
      32: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      35: areturn

  public static java.lang.String Test24();
    Code:
       0: new           #5                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #6                  // Method java/lang/StringBuilder."":()V
       7: astore_0
       8: iconst_0
       9: istore_1
      10: iload_1
      11: bipush        100
      13: if_icmpge     31
      16: ldc           #2                  // String aiueo
      18: astore_2
      19: aload_0
      20: aload_2
      21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: pop
      25: iinc          1, 1
      28: goto          10
      31: aload_0
      32: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      35: areturn

  public static java.lang.String Test26();
    Code:
       0: new           #5                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #6                  // Method java/lang/StringBuilder."":()V
       7: astore_0
       8: iconst_0
       9: istore_1
      10: iload_1
      11: bipush        100
      13: if_icmpge     29
      16: aload_0
      17: ldc           #2                  // String aiueo
      19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: pop
      23: iinc          1, 1
      26: goto          10
      29: aload_0
      30: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      33: areturn
}

javapで出力された内容を解説します(SamplePlus編)

注目して欲しいのは2つ

  • newの数
  • 演算子がStringBuilderに変換(最適化)されている

演算子での文字連結は基本的にはStringBuilderに変換されるのです
ですので、演算子を積極的に使うことを推奨します
StringBuilderより演算子の方が読みやすいですよね

でもですね、newの数が無駄に多くなることがあります
その場合はインスタンス生成→解放の処理が無駄なので、素直にStringBuilderを使う方が良い場面もあります

演算子で良い場合、悪い場合を見ていきましょう!

バイトコードの参考
invokespecial:コンストラクタの呼び出し
invokevirtual:メソッドの呼び出し

ノーマル系

Test11

前置き
  • 1行で連結
  • String変数使用
    public static String Test11() {
        String  hoge = "aiueo";
        String  fuga = "kakikukeko";
        String  piyo = "sasisuseso";
        String  gabo;

        gabo = hoge + fuga + piyo;

        return gabo;
    }
  public static java.lang.String Test11();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #3                  // String kakikukeko
       5: astore_1
       6: ldc           #4                  // String sasisuseso
       8: astore_2
       9: new           #5                  // class java/lang/StringBuilder
      12: dup
      13: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      16: aload_0
      17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      20: aload_1
      21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: aload_2
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: astore_3
      32: aload_3
      33: areturn
解説

この1行で連結する形は、演算子でいいです

 

Test12

  • 1行で連結
  • 文字列使用
    public static String Test12() {
        String  gabo;

        gabo = "aiueo" + "kakikukeko" + "sasisuseso";

        return gabo;
    }
  public static java.lang.String Test12();
    Code:
       0: ldc           #9                  // String aiueokakikukekosasisuseso
       2: astore_0
       3: aload_0
       4: areturn

これも1行で連結する形ですね
しかも、#9のところを見れば分かるように、コンパイル時点でaiueokakikukekosasisusesoを準備してくれてます
なので演算子でいいです

 

Test13

  • 複数行で連結
  • String変数使用
    public static String Test13() {
        String  hoge = "aiueo";
        String  fuga = "kakikukeko";
        String  piyo = "sasisuseso";
        String  gabo;

        gabo = "";
        gabo += hoge;
        gabo += fuga;
        gabo += piyo;

        return gabo;
    }
  public static java.lang.String Test13();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #3                  // String kakikukeko
       5: astore_1
       6: ldc           #4                  // String sasisuseso
       8: astore_2
       9: ldc           #10                 // String
      11: astore_3
      12: new           #5                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      19: aload_3
      20: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: aload_0
      24: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_3
      31: new           #5                  // class java/lang/StringBuilder
      34: dup
      35: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      38: aload_3
      39: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      42: aload_1
      43: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      46: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      49: astore_3
      50: new           #5                  // class java/lang/StringBuilder
      53: dup
      54: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      57: aload_3
      58: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      61: aload_2
      62: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      65: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      68: astore_3
      69: aload_3
      70: areturn

Test11()を複数行で連結にした形です
複数行にするとnewを3個も呼び出すので、無駄になります

1行で連結するか、StringBuilderを使いましょう

 

Test14

  • 複数行で連結
  • 文字列使用
    public static String Test14() {
        String  hoge = "aiueo";
        String  fuga = "kakikukeko";
        String  piyo = "sasisuseso";
        String  gabo;

        gabo = "";
        gabo += "aiueo";
        gabo += "kakikukeko";
        gabo += "sasisuseso";

        return gabo;
    }

  public static java.lang.String Test14();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #3                  // String kakikukeko
       5: astore_1
       6: ldc           #4                  // String sasisuseso
       8: astore_2
       9: ldc           #10                 // String
      11: astore_3
      12: new           #5                  // class java/lang/StringBuilder
      15: dup
      16: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      19: aload_3
      20: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: ldc           #2                  // String aiueo
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: astore_3
      32: new           #5                  // class java/lang/StringBuilder
      35: dup
      36: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      39: aload_3
      40: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      43: ldc           #3                  // String kakikukeko
      45: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      48: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      51: astore_3
      52: new           #5                  // class java/lang/StringBuilder
      55: dup
      56: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      59: aload_3
      60: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      63: ldc           #4                  // String sasisuseso
      65: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      68: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      71: astore_3
      72: aload_3
      73: areturn

これもTest12()を複数行で連結にした形です
先ほどと同じように複数行にするとnewを3個も呼び出すので、無駄になります

1行で連結するか、StringBuilderを使いましょう

 

Test15

  • 1行で連結
  • String変数と文字列の混合使用
    public static String Test15() {
        String  hoge = "aiueo";
        String  piyo = "sasisuseso";
        String  gabo;

        gabo = hoge + "kakikukeko" + piyo + "tatituteto";

        return gabo;
    }
  public static java.lang.String Test15();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #4                  // String sasisuseso
       5: astore_1
       6: new           #5                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      13: aload_0
      14: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      17: ldc           #3                  // String kakikukeko
      19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: aload_1
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: ldc           #11                 // String tatituteto
      28: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      31: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      34: astore_2
      35: aload_2
      36: areturn

変数と文字列が混在していますが、1行連結ですので、newも1個ですね
演算子で問題ありません

 

ループ系

Test21

  • ループ使用
  • String変数使用
  • ループの【外】でString変数定義
  • 代入系
    public static String Test21() {
        String  hoge = "aiueo";
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            gabo = hoge;
        }

        return gabo;
    }
  public static java.lang.String Test21();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #10                 // String
       5: astore_1
       6: iconst_0
       7: istore_2
       8: iload_2
       9: bipush        100
      11: if_icmpge     22
      14: aload_0
      15: astore_1
      16: iinc          2, 1
      19: goto          8
      22: aload_1
      23: areturn

hogeをgoboへ100回代入してますけど、意味はないです
19:8:へgotoしているので、9:16:for文の処理です
特にnewしているわけでもないので、問題ないですね

演算子の使用でOKです

 

Test22

  • ループ使用
  • String変数使用
  • ループの【外】でString変数定義
  • 足していく系
    public static String Test22() {
        String  hoge = "aiueo";
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            gabo += hoge;
        }

        return gabo;
    }
  public static java.lang.String Test22();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #10                 // String
       5: astore_1
       6: iconst_0
       7: istore_2
       8: iload_2
       9: bipush        100
      11: if_icmpge     39
      14: new           #5                  // class java/lang/StringBuilder
      17: dup
      18: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      21: aload_1
      22: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      25: aload_0
      26: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      29: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      32: astore_1
      33: iinc          2, 1
      36: goto          8
      39: aload_1
      40: areturn

Test21()を代入から常に連結に変えたものです

for文の処理はどこからどこまででしょうか?

36:でgotoしているので、9:33:for文の処理ですね

ということは、毎回newしちゃってます
無駄ですね...

連結しまくるなら、StringBuilderを使いましょう

 

Test23

  • ループ使用
  • String変数使用
  • ループの【中】でString変数定義
  • 代入系
    public static String Test23() {
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            String  hoge = "aiueo";
            gabo = hoge;
        }

        return gabo;
    }
  public static java.lang.String Test23();
    Code:
       0: ldc           #10                 // String
       2: astore_0
       3: iconst_0
       4: istore_1
       5: iload_1
       6: bipush        100
       8: if_icmpge     22
      11: ldc           #2                  // String aiueo
      13: astore_2
      14: aload_2
      15: astore_0
      16: iinc          1, 1
      19: goto          5
      22: aload_0
      23: areturn

Test21()の変数hogeの宣言位置がfor文の中に移動しました

しかし、newしていませんね

これは"aiueo"の値固定なので、11:で準備してくれてますね

演算子でいいでしょう

 

Test24

  • ループ使用
  • String変数使用
  • ループの【中】でString変数定義
  • 足していく系
    public static String Test24() {
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            String  hoge = "aiueo";
            gabo += hoge;
        }

        return gabo;
    }
  public static java.lang.String Test24();
    Code:
       0: ldc           #10                 // String
       2: astore_0
       3: iconst_0
       4: istore_1
       5: iload_1
       6: bipush        100
       8: if_icmpge     39
      11: ldc           #2                  // String aiueo
      13: astore_2
      14: new           #5                  // class java/lang/StringBuilder
      17: dup
      18: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      21: aload_0
      22: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      25: aload_2
      26: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      29: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      32: astore_0
      33: iinc          1, 1
      36: goto          5
      39: aload_0
      40: areturn

Test22()の変数hogeの宣言位置がfor文の中に移動しましたが、形は殆ど変わりません

for文の中で毎回newしています

StringBuilderを使いましょう
StringBuilderの宣言はfor文の外でしましょう

 

Test25

  • ループ使用
  • 文字列使用
  • ---
  • 代入系
    public static String Test25() {
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            gabo = "aiueo";
        }

        return gabo;
    }
  public static java.lang.String Test25();
    Code:
       0: ldc           #10                 // String
       2: astore_0
       3: iconst_0
       4: istore_1
       5: iload_1
       6: bipush        100
       8: if_icmpge     20
      11: ldc           #2                  // String aiueo
      13: astore_0
      14: iinc          1, 1
      17: goto          5
      20: aload_0
      21: areturn

Test21()での変数hogeが直接"aiueo"の文字列になりました
最適化内容はほぼ同じ

演算子の使用でOKです

 

Test26

  • ループ使用
  • 文字列使用
  • ---
  • 足していく系
    public static String Test26() {
        String  gabo = "";

        for(int i=0; i < 100; i++) {
            gabo += "aiueo";
        }

        return gabo;
    }
  public static java.lang.String Test26();
    Code:
       0: ldc           #10                 // String
       2: astore_0
       3: iconst_0
       4: istore_1
       5: iload_1
       6: bipush        100
       8: if_icmpge     37
      11: new           #5                  // class java/lang/StringBuilder
      14: dup
      15: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      18: aload_0
      19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: ldc           #2                  // String aiueo
      24: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      27: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      30: astore_0
      31: iinc          1, 1
      34: goto          5
      37: aload_0
      38: areturn

Test22()での変数hogeが直接"aiueo"の文字列になりました
最適化内容はほぼ同じで、毎回newしちゃってます
無駄ですね...

連結しまくるなら、StringBuilderを使いましょう

 

 

広告




 

javapで出力された内容を解説します(SampleBuilder編)

つぎに、StringBuilderを使った場合を見ます
バイトコードに展開されてもStringBuilderなので、ソースコードとバイトコードに大きな違いは出ませんが、一応見てみましょう

注目して欲しいのはこれ

  • newの数

 

参考
invokespecial:コンストラクタの呼び出し
invokevirtual:メソッドの呼び出し

ノーマル系

Test11

前置き
  • 1行で連結
  • String変数使用
    public static String Test11() {
        String  hoge = "aiueo";
        String  fuga = "kakikukeko";
        String  piyo = "sasisuseso";
        StringBuilder  gabo = new StringBuilder();

        gabo.append(hoge);
        gabo.append(fuga);
        gabo.append(piyo);

        return gabo.toString();
    }
  public static java.lang.String Test11();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #3                  // String kakikukeko
       5: astore_1
       6: ldc           #4                  // String sasisuseso
       8: astore_2
       9: new           #5                  // class java/lang/StringBuilder
      12: dup
      13: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      16: astore_3
      17: aload_3
      18: aload_0
      19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: pop
      23: aload_3
      24: aload_1
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: pop
      29: aload_3
      30: aload_2
      31: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      34: pop
      35: aload_3
      36: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      39: areturn
解説

演算子の時よりも少し処理が多いですね
やっぱり1行で連結する形は、演算子がいいですね

 

Test12

  • 1行で連結
  • 文字列使用
    public static String Test12() {
        StringBuilder  gabo = new StringBuilder();

        gabo.append("aiueo");
        gabo.append("kakikukeko");
        gabo.append("sasisuseso");

        return gabo.toString();
    }
  public static java.lang.String Test12();
    Code:
       0: new           #5                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #6                  // Method java/lang/StringBuilder."":()V
       7: astore_0
       8: aload_0
       9: ldc           #2                  // String aiueo
      11: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: pop
      15: aload_0
      16: ldc           #3                  // String kakikukeko
      18: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: pop
      22: aload_0
      23: ldc           #4                  // String sasisuseso
      25: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: pop
      29: aload_0
      30: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      33: areturn

これもTest11()と同じく、演算子の時よりも少し処理が多くなっていますね
やっぱり1行で連結する形は、演算子がいいですね

 

Test13

※無し

 

Test14

※無し

 

Test15

  • 1行で連結
  • String変数と文字列の混合使用
    public static String Test15() {
        String  hoge = "aiueo";
        String  piyo = "sasisuseso";
        StringBuilder  gabo = new StringBuilder();

        gabo.append(hoge);
        gabo.append("kakikukeko");
        gabo.append(piyo);
        gabo.append("tatituteto");

        return gabo.toString();
    }
  public static java.lang.String Test15();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: ldc           #4                  // String sasisuseso
       5: astore_1
       6: new           #5                  // class java/lang/StringBuilder
       9: dup
      10: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      13: astore_2
      14: aload_2
      15: aload_0
      16: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: pop
      20: aload_2
      21: ldc           #3                  // String kakikukeko
      23: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: pop
      27: aload_2
      28: aload_1
      29: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      32: pop
      33: aload_2
      34: ldc           #9                  // String tatituteto
      36: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      39: pop
      40: aload_2
      41: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      44: areturn

これもTest11()と同じく、演算子の時よりも少し処理が多くなっていますね
やっぱり1行で連結する形は、演算子がいいですね

 

ループ系

Test21

※無し

 

Test22

  • ループ使用
  • String変数使用
  • ループの【外】でString変数定義
  • 足していく系
    public static String Test22() {
        String  hoge = "aiueo";
        StringBuilder  gabo = new StringBuilder();

        for(int i=0; i < 100; i++) {
            gabo.append(hoge);
        }

        return gabo.toString();
    }
  public static java.lang.String Test22();
    Code:
       0: ldc           #2                  // String aiueo
       2: astore_0
       3: new           #5                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #6                  // Method java/lang/StringBuilder."":()V
      10: astore_1
      11: iconst_0
      12: istore_2
      13: iload_2
      14: bipush        100
      16: if_icmpge     31
      19: aload_1
      20: aload_0
      21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: pop
      25: iinc          2, 1
      28: goto          13
      31: aload_1
      32: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      35: areturn

これは演算子のバイトコードよりも処理が少なくなっています
しかし、処理の少なさよりも見てほしいのはnewの位置です

for文の処理はどこからどこまででしょうか?
28:でgotoしているので、14:25:for文の処理ですね

ということは、演算子の時と違ってnewは1回だけです

ループ文を使って連結しまくる処理の場合は、StringBuilderを使いましょう

 

Test23

※無し

 

Test24

  • ループ使用
  • String変数使用
  • ループの【中】でString変数定義
  • 足していく系
    public static String Test24() {
        StringBuilder  gabo = new StringBuilder();

        for(int i=0; i < 100; i++) {
            String  hoge = "aiueo";
            gabo.append(hoge);
        }

        return gabo.toString();
    }
  public static java.lang.String Test24();
    Code:
       0: new           #5                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #6                  // Method java/lang/StringBuilder."":()V
       7: astore_0
       8: iconst_0
       9: istore_1
      10: iload_1
      11: bipush        100
      13: if_icmpge     31
      16: ldc           #2                  // String aiueo
      18: astore_2
      19: aload_0
      20: aload_2
      21: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: pop
      25: iinc          1, 1
      28: goto          10
      31: aload_0
      32: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      35: areturn

演算子の場合はfor文の中でnewを何度もしていましたが、StringBuilderを使った場合はnewは最初の1回だけです

ループで連結しまくるなら、StringBuilderを使いましょう

 

Test25

※無し

 

Test26

  • ループ使用
  • 文字列使用
  • ---
  • 足していく系
    public static String Test26() {
        StringBuilder  gabo = new StringBuilder();

        for(int i=0; i < 100; i++) {
            gabo.append("aiueo");
        }

        return gabo.toString();
    }
  public static java.lang.String Test26();
    Code:
       0: new           #5                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #6                  // Method java/lang/StringBuilder."":()V
       7: astore_0
       8: iconst_0
       9: istore_1
      10: iload_1
      11: bipush        100
      13: if_icmpge     29
      16: aload_0
      17: ldc           #2                  // String aiueo
      19: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: pop
      23: iinc          1, 1
      26: goto          10
      29: aload_0
      30: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      33: areturn

演算子の場合はfor文の中でnewを何度もしていましたが、StringBuilderを使った場合はnewは最初の1回だけです

ループで連結しまくるなら、StringBuilderを使いましょう

 

 

広告




 

まとめ

まとめると、

  • Javaの文字連結は演算子を使い、コンパイル時の最適化に任せる方が良い
  • StringBuilderを使うと最適化してもらえないので、無駄な処理になることがある
  • とは言っても、演算子ではダメな場面もあるので、その時は自分でStringBuilderを使う
演算子とStringBuilderの結果まとめ
内容 演算子 StringBuilder
Test11
1行で連結
String変数使用


1行連結は演算子推奨!
Test12
1行で連結
文字列使用


1行連結は演算子推奨!
Test13
複数行で連結
String変数使用


複数行連結ならStringBuilder
もしくは1行連結に書き直すなら演算子が使える
Test14
複数行で連結
文字列使用


複数行連結ならStringBuilder
もしくは1行連結に書き直すなら演算子が使える
Test15
1行で連結
String変数と文字列の混合使用


1行連結は演算子推奨!
Test21
ループ使用
String変数使用
ループの【外】でString変数定義
代入系

ループ処理だけど同じ値を代入しているだけなので、何度もnewしないから演算子でOK
(現実的にはこんな処理を書くこと自体がおかしいけどねwww)
Test22
ループ使用
String変数使用
ループの【外】でString変数定義
足していく系

ループの中で毎回連結するならStringBuilderを使いましょう

Test23
ループ使用
String変数使用
ループの【中】でString変数定義
代入系

Test21と同じく、固定値を代入するだけなので演算子でOK
Test24
ループ使用
String変数使用
ループの【中】でString変数定義
足していく系

ループの中で毎回連結するならStringBuilderを使いましょう
Test25
ループ使用
文字列使用
---
代入系

Test21と同じく、固定値を代入するだけなので演算子でOK
Test26
ループ使用
文字列使用
---
足していく系

ループの中で毎回連結するならStringBuilderを使いましょう

 

さいごに、

実はですね、この記事では触れていないことがあります
それは処理速度です

今回の記事はバイトコードでのnewの位置や数に着目しましたが、処理速度も重要な要素です

newでインスタンス作成→解放が処理コストかかるはずなので、newの数が多いと処理時間もかかるはずですが、
とは言え、処理速度が気になる場合には今回のようにまずバイトコードを見た上で、処理時間を計測するとよりよりソースコードになるでしょう

 

今回見た内容はJava8の場合です
将来的にどうなるかは分かりません

どんな場合であっても、バイトコードが見られるならば、自分の目で確認すればいいだけのことです
javapを使ってバイトコードを見ることを覚えてください

 

 

個人的にJavaに対する感想は...なんか分かりづらいんですよねぇ~

演算子とStringBuilderを比較するというのが、なんか対称性がなくて、かなり変な感じがします(←この感覚分かる人には分かるでしょうけど、分からん人には分かんないですよねwww)

毎回毎回バイトコードを見るわけにはいかないですけど、ちょっとややこしいところはバイトコード見たり処理速度を見たりしましょう

 

あと、Javaだけじゃないですけど、プログラミングをする場合、コンパイラが最適化してくれる場合はその最適化が効くような書き方をすると良いですよ
C#はそういう思想だったはずですよね

 

今回はここまで!

 

 


 

プログラミング のレッスンに興味がある方、レッスン内容を聞いてみたい方、なんなりとお問い合わせください。
無料体験レッスンもありますのでお気軽にどうぞ!!!

 

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

ABOUTこの記事をかいた人

Windows/Mac/Linuxを使う現役システムエンジニア&プログラマ。オープン系・組み込み系・制御系・Webシステム系と幅広い案件に携わる。C言語やC#やJava等数多くのコンパイラ言語を経験したが、少し飽きてきたので、最近はRubyやPython、WordPressなどのWeb系を修得中。初心者向けのプログラミング教室も運営中。オンライン・対面・出張等でプログラミングをレッスンします。