文字列結合はStringBuilderクラスやStringBufferクラスを使うことが一般的だと思いますが、
「+演算子による文字列結合」と「Stringクラスのconcatメソッド」でも文字列結合ができるので、
各処理速度をJava17で比較してみました。
"test"という文字を100万回結合するコードを作成しました。
-
public class StringTest {
-
public static void main(String[] args) {
-
plus();
-
concat();
-
builder();
-
buffer();
-
}
-
public static void plus() {
-
long start = System.currentTimeMillis();
-
String txt = "test";
-
for (int i=0; i<1000000; i++) {
-
txt += "test";
-
}
-
long end = System.currentTimeMillis();
-
System.out.println("+:" + (end - start) + "ms");
-
}
-
public static void concat() {
-
long start = System.currentTimeMillis();
-
String txt = "test";
-
for (int i=0; i<1000000; i++) {
-
txt = txt.concat("test");
-
}
-
long end = System.currentTimeMillis();
-
System.out.println("concat:" + (end - start) + "ms");
-
}
-
public static void builder() {
-
long start = System.currentTimeMillis();
-
StringBuilder sb = new StringBuilder("test");
-
for (int i=0; i<1000000; i++) {
-
sb.append("test");
-
}
-
long end = System.currentTimeMillis();
-
System.out.println("StringBuilder:" + (end - start) + "ms");
-
}
-
public static void buffer() {
-
long start = System.currentTimeMillis();
-
StringBuffer sb = new StringBuffer("test");
-
for (int i=0; i<1000000; i++) {
-
sb.append("test");
-
}
-
long end = System.currentTimeMillis();
-
System.out.println("StringBuffer:" + (end - start) + "ms");
-
}
-
}
■パフォーマンス比較結果
+演算子による結合 | 219521ms |
concatメソッド | 239762ms |
StringBuilder | 14ms |
StringBuffer | 24ms |
■テスト結果の考察
StringBuilder、StringBufferによる文字列結合は圧倒的に高速に処理されていることがわかります。
理由としては、格納された文字列の長さと内容を変更できるので、
1度インスタンスを生成すれば文字列結合を実行する度にインスタンスを生成する必要がないためです。
対して「+演算子による文字列結合」と「Stringクラスのconcatメソッド」では、
文字列結合を実行する度にインスタンスを生成するため、処理がかなり遅くなります。
・「Stringクラスのconcatメソッド」より「+による結合」が早い理由
Java9以降では「+による結合」の処理が効率化されました。
1回の文字列結合中に1回のJavaインスタンスの生成と配列の確保が行われるようになりました。
一方、「Stringクラスのconcatメソッド」では、
1回の文字列結合中に1回のJavaインスタンスの生成と3回の配列の確保が行われるようになっています。
配列の確保の回数が少ないため、「+による結合」の方が処理速度が速くなりました。
・StringBuilderとStringBufferの比較
公式リファレンスでは、スレッドセーフが不要な場合は、
StringBufferより高速に実行されるStringBuilderを使用することが推奨されています。
理由としては、処理自体は大差ないのですが、StringBufferはスレッドセーフであるための処理を実行しており、
効率が悪くなってしまうためです。
StringBufferのメソッドの殆どはsynchronized修飾子が付与されているため、メソッドが同時に実行されません。
つまりメソッドを実行するたびにStringBufferオブジェクトのロックが行われるということです。
この処理によってスレッドセーフを実現しています。
以上の処理を実行しない分、StringBuilderの方が高速に実行されます。