Javaの文字列結合パフォーマンス その2

2015年3月29日日曜日

Java パフォーマンス

さて、以下のようなコードではどちらのほうが処理が速くなるだろうか。

1. +演算子で結合
String s = s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9;

2. StringBuilderで結合
StringBuilder sb = new StringBuilder();
sb.append(s1);
sb.append(s2);
sb.append(s3);
sb.append(s4);
sb.append(s5);
sb.append(s6);
sb.append(s7);
sb.append(s8);
sb.append(s9);
String s = sb.toString();

Core i5 1.6GHz環境で実行したところ、1m秒あたりの処理回数は以下となった。

1. +演算子で結合
15000 ops/msec
2. StringBuilderで結合
 7000 ops/msec

+演算子のほうが倍以上速いことになる。
なぜ、このような差が出てしまったのだろうか。
String s = s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9;
をコンパイルした結果を擬似的にJavaのコードで表すと以下になる。
String s = (new StringBuilder()).append(s1).append(s2).append(s3)
                                .append(s4).append(s5).append(s6)
                                .append(s7).append(s8).append(s9)
                                .toString();
これと2. StringBuilderで結合との違いはsb変数がappendメソッド呼び出し時にいちいち登場しないところにある。
これはappendメソッドが戻り値として、呼び出し先のオブジェクト参照を返すことをうまく利用している。
毎回、sb変数を参照する場合、 メソッド呼び出しを実行する前にオペランドスタックに毎回、sb変数をプッシュする必要が生じてしまう。

というわけで以下の書き方をすると、+演算子で結合した場合と同じ処理速度になる。

3. StringBuilderで結合改良
StringBuilder sb = new StringBuilder();
sb.append(s1)
  .append(s2)
  .append(s3)
  .append(s4)
  .append(s5)
  .append(s6)
  .append(s7)
  .append(s8)
  .append(s9);
String s = sb.toString();

処理速度とコードの見通しを考えると+演算子で結合したほうがよさそうだ。