文字列間の 「+」 演算子

先日、静的な文字列に対するJava演算子の振る舞いについて注意を受けたので、今更ながらメモを残しておく。

 

下記のコード1とコード2がどのようにコンパイルされるか。
コード1 : aからzまでのアルファベットを「+」演算して結合文字列変数を作成する。

public class StringTest1 {
  public static void main(String[] args) {
    String str = "a" + "b" + "c" + "d" + "e" + "f" + "g" + "h" + "i" + "j" + "k" + "l" + "m" + "n" + "o" + "p" + "q" + "r" + "s" + "t" + "r" + "u" + "v" + "w" + "x" + "y" + "z";
    System.out.println(str);
  }
}

コード2 : aからzまでのアルファベットを一つの文字列変数として記述する。

public class StringTest2 {
  public static void main(String[] args) {
    String str = "abcdefghijklmnopqrstruvwxyz";
      System.out.println(str);
  }
}

コンパイル後のクラスのファイルサイズ

-rw-r--r-- 1 user group  449 Jul  7 17:42 StringTest1.class
-rw-r--r-- 1 user group  449 Jul  7 17:42 StringTest2.class

コード1の逆アセンブル

$ javap StringTest1.class
Compiled from "StringTest1.java"
public class StringTest1 {
  public StringTest1();
  public static void main(java.lang.String[]);
}

コード2の逆アセンブル

$ javap StringTest2.class
Compiled from "StringTest2.java"
public class StringTest2 {
  public StringTest2();
  public static void main(java.lang.String[]);
}

コンパイル後のコード1とコード2は同じものであることがわかる。

 

次に、「+」演算子をStringBuilderのappendメソッドに変更して、実行時間を計測する。

コード1 改 : コード1で実行時間を計測するようにした。

public class StringTest1 {
  public static void main(String[] args) {
    long startTime = System.nanoTime();
    String str = "a" + "b" + "c" + "d" + "e" + "f" + "g" + "h" + "i" + "j" + "k" + "l" + "m" + "n" + "o" + "p" + "q" + "r" + "s" + "t" + "r" + "u" + "v" + "w" + "x" + "y" + "z";
    System.out.println(str);
    long endTime = System.nanoTime();
    System.out.println(endTime - startTime);
  }
}

コード3 : コード1改の「+」演算子をStringBuilderのappendメソッドに変更した。

public class StringTest3 {
  public static void main(String[] args) {
    long startTime = System.nanoTime();
    StringBuilder build = new StringBuilder("a")
      .append("b").append("c").append("d").append("e").append("f")
      .append("g").append("h").append("i").append("j").append("k")
      .append("l").append("m").append("n").append("o").append("p")
      .append("q").append("r").append("s").append("t").append("u")
      .append("v").append("w").append("x").append("y").append("z");
    System.out.println(build);
    long endTime = System.nanoTime();
    System.out.println(endTime - startTime);
  }
}

コード1実行:

$ java StringTest1
abcdefghijklmnopqrstruvwxyz
178237

コード3実行:

$ java StringTest3
abcdefghijklmnopqrstuvwxyz
248851

StringBuilderを使用するとかえって遅くなることがわかる。

 

実行時に動的に変化しない文字列変数に関しては、コンパイラが最適化してくれるので、「+」演算子を除去しても意味がなく、StringBuilderを使用するとかえって効率が悪くなる。

投稿日: