Edited at

Javaの文字列結合効率化を確認

More than 3 years have passed since last update.

Javaで大量のテキストを処理する機会があったので、文字列結合の効率化について復習しておこう。


環境&やること


  • Java1.8


  • JODEでデコンパイルして動きを見よう


文字列結合いろいろ


  • "+"を使う

  • String.concat()を使う

  • StringBuffer/StringBuilderを使う


文字列結合

String a = "aaa";

String b = "bbb";
String str;
//"+"を使う
str = a + b;
//concatを使う
str = a.concat(b);
//StringBuilderを使う
str = new StringBuilder(a).append(b).toString();

concat()は新しくStringをnewして返すメソッド。

StringBuffer/Builderは可変長文字列を扱うクラスで、appendされた文字列をせっせとバッファに詰め込みます(いちいちnewしない)。

問題なのが"+"で、これはコンパイラの最適化によって書き換わります。使い方を間違えると大変。


ダメな例

早速やらかしてみましょう。



String str = "";

//やらかした例
for(int i = 0; i < 10000; i++){
str += a + b;
}


デコンパイル

String str = "";

for (int i = 0; i < 10000; i++)
str = new StringBuilder(str).append(a).append(b).toString();

StringBuilderを使った文字列結合は速いんですが、そもそもStringBuilderをnewすること自体はそれなりにコストがかかります。ループの中でnewしちゃだめです。


インスタンス使いまわす

StringBuilder sb = new StringBuilder();

for (int i = 0; i < 10000; i++) {
sb.setLength(0);
str = sb.append(str).append(a).append(b).toString();
}


定数の結合

もう一つ注意点。

定数は最適化の段階で一つにまとめてくれます。なので最速。最速というか結合じゃないし。



final String FA = "finalA";

final String FB = "finalB";
String a = "A";
String b = "B";
String str = "";

str = "A" + "B"; //文字列
str = a + b; //変数の結合
str = FA + FB; //定数の結合
str = a + FA + FB; //変数+定数
str = FA + FB + a; //定数+変数



デコンパイル

str = "AB";

str = new StringBuilder(a).append(b).toString();
str = "finalAfinalB";
str = new StringBuilder(a).append("finalA").append("finalB").toString();
str = new StringBuilder("finalAfinalB").append(a).toString();

ただ、定数と変数が混ざった下2行を見てみると、変数が混ざる前は結合されてますが、変数以降はappendになってますね。


まとめ


  • ループ内での"+"を使った文字列結合は注意

  • 定数と変数を混ぜる場合も注意

  • そうは言っても何万回も繰り返さない処理なら可読性UPのために"+"使ってもいいよね


なんで今さら?

Q. Javaプログラマーにとっては何を今更という内容かもしれないが、なんで書いた?

A. 自分で書いたコード見直してたら思いっきりやらかしてたから。