【Java】文字列を10万回連結してみた【String vs StringBuilder】

f:id:shogonir:20180204132011p:plain

 

目次

  1. この記事の目的
  2. 文字列連結の2種類の仕方
  3. パフォーマンスを比較する
  4. 10万回ではなく1000回であれば
  5. 結論

 

1. この記事の目的

Javaで文字列を連結する際は、StringStringBuilderのどちらを使えばいいのかを考えたいと思います。
StringStringBuilder の2つのクラスについては色々な主張を見かけます。例えば、
「文字列の連結を何回も行う時は String ではなく StringBuilder を使え」
「Java9からは最適化の方法が変わったからString使っていい」
などです。実際どっちが速いのか実験してみました。

サンプルコードをGitHubにあげました。
Dockerがある環境で python execute_multi.py で実行してください。

 

github.com

 

2. 文字列連結の2種類の仕方

StringStringBuilder の文字列の連結の方法を紹介します。
まずは String から、こちらはおなじみかと思います。

 

public class StringConcatWithOperator {

    public static void main (String[] args) {
        
        long startTime = System.currentTimeMillis();

        String message = "";

        for (int i = 0; i < 100 * 1000; i++) {
            message += "a";
        }
        
        long endTime = System.currentTimeMillis();

        System.out.println("    " + (endTime - startTime) + "ms");
    }
}

 

String+ 演算子で文字列を連結しています。
この時、毎回 String のオブジェクトを作成しては捨てています。
このオブジェクトの作成にコストがかかるので遅くなります。

続いて StringBuilder です。

 

public class StringConcatWithBuilder {

    public static void main (String[] args) {
        
        long startTime = System.currentTimeMillis();

        StringBuilder builder = new StringBuilder();

        for (int i = 0; i < 100 * 1000; i++) {
            builder.append("a");
        }

        String message = builder.toString();
        
        long endTime = System.currentTimeMillis();

        System.out.println("    " + (endTime - startTime) + "ms");
    }
}

 

StringBuilderappend で文字列を連結しています。
この時は "a" のオブジェクトも使い回しですし、 StringBuilderインスタンスも1つだけです。

さて、パフォーマンスの差はどのようになるのでしょうか。

 

3. パフォーマンスを比較する

実際に文字列を10万回連結した際の速度をJava8とJava9で比較しました。

 

バージョン String StringBuilder
Java8 10263ms 9ms
Java9 1862ms 13ms

 

ここから分かったことを2つまとまます。

 

 

まず StringBuilder の方が速い件は、先述のオブジェクトの使い回しが原因です。

String の連結の最適化については、他の記事によいものがありますので探してみてください。

 

4. 10万回ではなく1000回であれば

先ほどの実験では10万回文字列を連結しましたが、正直少し現実的ではありません。
そこで、1000回ぐらいだと String の方が速いんじゃないの?ということでこちらも実験します。

結果は以下の通りです。

 

バージョン String StringBuilder
Java8 5ms 1ms
Java9 121ms 1ms

 

ここから分かったことを2つまとまます。

 

 

Java9の最適化はDynamicInvokeという方法らしいのですが、文字列の数が多くなるほど効くようです。

 

5. 結論

結論は、「場合による」。

まず、数万以上の文字列を連結を行う場合は StringBuilder を使うべきです。
100分の1程度の時間で文字列の連結を行えるからです。

千程度の文字列を連結する際も、 StringBuilder の方が速いは速いです。
アプリやゲームなどで、1フレームで使える時間が限られている場合は StringBuilder がいいです。
Java9だと100ms以上かかる場合もあるからです。
そこまでパフォーマンスにこだわらない場合は、プロジェクトメンバーの技術力や可読性と相談です。