すがブロ

sugamasaoのhatenablogだよ

JDK5の機能(3)

前回→id:seiunsky:20060709:1152473178
地味編。
StringBuilderクラスがある。
あぁ、わかってる。わかってるよ。これはJavaの話なんだ。だからどうか落ち着いて聞いて欲しい。
JDK5になって導入されたこのクラス。スレッドアンセーフだけど高速な動作ができるようになっている。
お馴染みのStringBufferはスレッドセーフである。
また、JDK5になってこの辺りのクラス階層が変更されていて、AbstractStringBuilderというクラスを継承する形でStringBufferやStringBuilderが実装されている。なぜかJDK5のJavaDocには書いてないが。また、Appendableなどのインターフェイスも新たに導入された。
というわけで、AbstractStringBuilderを実装している二つのクラス(StringBuilderとStringBuffer)は使う面では全く同じ動作をする。違いはsyncrhonizedが付いているかどうか。逆に言うと、速度についてもその部分以外は変わらないってことだね。
ちょっと簡単に計測してみた。以下がそのソースコード

long time;
StringBuffer sbuffer = new StringBuffer();
StringBuilder sbuilder = new StringBuilder();


// STringBuffer
time = System.currentTimeMillis();
for (int i = 0; i < 500000; i++) {
	sbuffer.append(i);
}
System.out.println("StringBuffer : " + (System.currentTimeMillis() - time)
		+ "ミリ秒");

// StringBuilder
time = System.currentTimeMillis();
for (int i = 0; i < 500000; i++) {
	sbuilder.append(i);
}
System.out.println("StringBuilder : " + (System.currentTimeMillis() - time)
		+ "ミリ秒");

で、ついでなのでStringBufferなどの宣言の時にバッファ数(バイト数?)を指定して計測するとどの程度高速になるのか試してみた。500000回繰り返す合計の桁数がよくわからんのでその10倍の値で実験。以下に宣言部分を書いておく。ま、この程度確保しておけばデフォルトに比べりゃだいぶマシだろう。

StringBuffer sbuffer = new StringBuffer(5000000);
StringBuilder sbuilder = new StringBuilder(5000000);

で、実験結果。誤差をなくすために5回繰り返した平均値を書いておく。

  • バッファ指定なし
    • StringBuffer:242ミリ秒
    • StringBuilder:187ミリ秒
  • バッファ指定あり
    • StringBuffer:112ミリ秒
    • StringBuilder:81ミリ秒

まとめ。
StringBuilderの方が大体2〜3割は高速なようだ。ただ、もともと異常にコストの掛かるものでもないので変える事で劇的にパフォーマンスが良くなるってことは無いだろう。……ただ、意識して使っていけばチリも積もるかもしれない。
また、バッファ指定をした場合、指定なしの時に比べて2倍以上のパフォーマンスを得られた。つまり、普段バッファ指定なしのStringBufferを使ってある程度の規模以上の文字列を操作しているなら、これを機にバッファ指定ありのStringBuilderを使ってみてはどうだろうか。
最低と最速の差は3倍もの差があるのだから。
ちなみに、バッファサイズは16から始まって倍々に増えていくはずなので2の二乗計算である程度のサイズを考えるとラクができるかもしれない(例えば、300文字必要なら512とっとけばよくね? みたいな)。