[Java] 演算子: +演算子による文字列結合(StringBuilder)

+演算子による文字列連結は非効率とのこと。

  • 新しめの Java での単発の文字列連結は、内部的に StringBuilder オブジェクトに変換されるためシンプルに+演算子を使うべき。
  • ループ内の文字列連結では StringBuilder が繰り返し生成されるため非効率になる。

以下同じ出力を得るための試行。

% java --version
openjdk 16 2021-03-16
OpenJDK Runtime Environment (build 16+36-2231)
OpenJDK 64-Bit Server VM (build 16+36-2231, mixed mode, sharing)

+演算子による文字列連結

package com.example.arrayloop;

public class ArrayLoop {
    public static void main(String[] args) throws Exception {
        var start = System.currentTimeMillis();

        int[] array = {50, 60, 70, 80};
        for (int mps : array) {
            var kmh = mps * 3600 / 1000;
            msg = "最大瞬間風速" + mps + "m = 時速" + kmh + "km";
            System.out.println(msg);
        }

        var end = System.currentTimeMillis();
        System.out.println((end - start)  + "ミリ秒");
    }
}

実行結果

最大瞬間風速50m = 時速180km
最大瞬間風速60m = 時速216km
最大瞬間風速70m = 時速252km
最大瞬間風速80m = 時速288km
18ミリ秒

一度の連結で、内部的には「元の文字列、連結する文字列、結果文字列」と合計3個の String オブジェクトを生成している。
ループで連結回数が増えた場合には、ガベージコレクションの増大に繋がり無視できなくなる。

StringBuilder

package com.example.arrayloop;

public class ArrayLoop {
    private static String msg;

    public static void main(String[] args) throws Exception {
        var start = System.currentTimeMillis();

        StringBuilder msg = new StringBuilder();
        int[] array = {50, 60, 70, 80};
        for (int mps : array) {
            var kmh = mps * 3600 / 1000;
            msg.append("最大瞬間風速").append(mps).append("m = 時速").append(kmh).append("km").append("\n");
            setMsg(msg.toString());
        }

        System.out.println(msg);

        var end = System.currentTimeMillis();
        System.out.println((end - start)  + "ミリ秒");
    }

    private static void setMsg(String msgString) {
        msg = msgString;
    }
}

実行結果

最大瞬間風速50m = 時速180km
最大瞬間風速60m = 時速216km
最大瞬間風速70m = 時速252km
最大瞬間風速80m = 時速288km

1ミリ秒

補遺

  • Stringbuffer クラスは、さらに排他制御を提供する。よってより低速。