web-dev-qa-db-ja.com

+ =は連結よりも効率的ですか?

私はチームの他の開発者によって作成されたコードを読んでいますが、彼らは文字列の連結に_+=_を使用することを好むようですが、読みやすいので.concat()を使用することを好みます。

なぜ.concat()を使用する方が良いのかについて議論を準備しようとしていますが、2つの間に効率の違いはありますか?

どのオプションを「すべき」ですか?

_public class Stuff {

    public static void main(String[] args) {

        String hello = "hello ";
        hello += "world";
        System.out.println(hello);

        String helloConcat = "hello ".concat("world");
        System.out.println(helloConcat);
    }
}
_
14
Jimmy

文字列はJavaでは不変であるため、_+_、_+=_、またはconcat(String)を実行すると、新しい文字列が生成されます。文字列が大きいほど時間がかかります。コピーする量が増え、より多くのガベージが生成されます。

今日のJavaコンパイラは、文字列の連結を最適化して最適化します。

_System.out.println("x:"+x+" y:"+y);
_

コンパイラはそれを次のように生成します。

_System.out.println((new StringBuilder()).append("x:").append(x).append(" y:").append(y).toString());
_

私のアドバイスは、保守と読み取りが簡単なコードを書くことです。

このリンクは、 StringBuilder vs StringBuffer vs String.concat --done right のパフォーマンスを示しています。

10
Buhake Sindi

それは問題ではないはずです。現代のJavaコンパイラ、JVM、およびJITは、違いが最小限になるようにコードを最適化します。より読みやすく、保守しやすいコードを作成するように努める必要があります。

9
darioo

@dariooと他のほとんどの回答に同意します。常に読みやすさ(および保守性)を最優先します。 (最新のJITコンパイラーは、このような単純なケースで問題が発生することはありません。)

ただし、これがプログラムに対応するバイトコードです。 (+=アプローチはStringBuilderになります。これは、文字列を作成するときに一般的に推奨されるアプローチです。)

// String hello = "hello";
0: ldc #2; //String hello 
2: astore_1

// hello += "world";
3: new #3; //class Java/lang/StringBuilder
6: dup
7: invokespecial #4; //Method StringBuilder."<init>"
10: aload_1
11: invokevirtual #5; //Method StringBuilder.append
14: ldc #6; //String world
16: invokevirtual #5; //Method StringBuilder.append
19: invokevirtual #7; //Method StringBuilder.toString

// System.out.println(hello);
22: astore_1
23: getstatic #8; //Field System.out
26: aload_1
27: invokevirtual #9; //Method PrintStream.println

// String helloConcat = "hello ".concat("world");
30: ldc #2; //String hello 
32: ldc #6; //String world
34: invokevirtual #10; //Method String.concat
37: astore_2

// System.out.println(helloConcat);
38: getstatic #8; //Field System.out
41: aload_2
42: invokevirtual #9; //Method PrintStream.println

45: return
5
aioobe

読みやすさという点では、あなたは非常に間違っていると思います。 _+_は.concat()に勝ちます。 _+=_を使用している場合は、ループに対して同じStringBuilderを維持する_StringBuilder.append_について検討することをお勧めします。

パフォーマンスの点では、concatは_+_よりも優れています。 1つまたはおそらく2つだけを使用する限り。

concatの場合、正しいサイズの_char[]_でStringオブジェクトを作成することになります。それはあなたが得ることができるのとほぼ同じくらい最適です。

_+_の場合、javacは、追加を行うためにStringBuilderを構築し、次にStringに変換するコードを生成します。 1.5から作成します:

  • StringBuilder(廃棄物)
  • StringBuilder(廃棄物)の初期_char[]_
  • 結果のシーケンスが長すぎる場合は、2番目に大きい_char[]_(無駄)
  • 結果のString
  • Stringの_char[]_。

ただし、読みにくいため、concatが使用されることはめったにありません。パフォーマンスは、他の状況と比較して、ほぼ確実に海の低下になります(ヒント:最適化する前に封筒の裏側を試してください)。

Concatは、2つの文字列を連結する場合に間違いなく高速な選択です。なぜ、javacが内部的に使用するのかわかりません。

(new StringBuilder(String.valueOf(s1))).append(s2).toString()

の代わりに

s1.concat(s2)

s1 + = s2の場合。同様の質問に対する私の答えを参照してください 連結演算子(+)vs concat()

1

あなたはあなたがあなたにとって最も短くそして最も明確であると思うことをするべきです。

しかし、あなたの興味のために。

    String hello = "hello " + "world";

コンパイルが2つの文字列を1つに結合したため、最速です。

これは、StringBuilderの作成を回避するため、2つの文字列で最速です。

    String helloConcat = "hello ".concat(world);

ただし、StringBuilderを使用して3つ以上の文字列がある場合は、暗黙的または明示的に最速です。

要約すると、ループ内にある場合を除いて+を使用します。ループ内にある場合は、パフォーマンスを向上させるためにStringBuilderを明示的に使用する可能性があります。

1
Peter Lawrey

私はこれを見つけました artical そしてこのテストをしました:

public static void main(String[] args) {
        String s1 = generateString();
        String s2 = generateString();
        String s3 = generateString();
        String s4 = generateString();
        String s5 = generateString();
        String s6 = generateString();

        long e = System.currentTimeMillis();
        for(int i=0;i<10000000;i++){
        //StringBuilder > concat> plus >StringBuffer >plusEqual(">"means faster than)
            //concatPlus(s1 , s2 , s3 , s4 , s5 , s6);//4204ms
            //concatBuilder(s1 , s2 , s3 , s4 , s5 , s6);//2562ms
            //concatBuffer(s1 , s2 , s3 , s4 , s5 , s6);//4610ms
            //concatPlusEqual(s1 , s2 , s3 , s4 , s5 , s6);//9843ms
            //concatConcat(s1 , s2 , s3 , s4 , s5 , s6);//3036ms
        }
        System.out.println(System.currentTimeMillis()-e);           
    }

public static String concatPlusEqual(String s1, String s2, String s3, String s4,
        String s5, String s6) {
       String result = "";
        result += s1;
        result += s2;
        result += s3;
        result += s4;
        result += s5;
        result += s6;
        return result;
}

    public static String concatConcat(String s1, String s2, String s3, String s4,
            String s5, String s6) {
        String result = new String();
        result.concat(s1);
        result.concat(s2);
        result.concat(s3);
        result.concat(s4);
        result.concat(s5);
        result.concat(s6);
        return result;
    }


    public static String concatBuffer(String s1, String s2, String s3, String s4,
            String s5, String s6) {
        return new StringBuffer(s1.length() + s2.length() + s3.length()
                + s4.length() + s5.length() + s6.length()).append(s1)
                .append(s2).append(s3).append(s4).append(s5).append(s6)
                .toString();
    }

    public static String concatBuilder(String s1, String s2, String s3, String s4,
            String s5, String s6) {
        return new StringBuilder(s1.length() + s2.length() + s3.length()
                + s4.length() + s5.length() + s6.length()).append(s1)
                .append(s2).append(s3).append(s4).append(s5).append(s6)
                .toString();
    }

    public static String concatPlus(String s1,String s2,String s3,String s4,String s5,String s6) {
        return s1 + s2 + s3 + s4 + s5 + s6;
    }
public static String generateString()
    {
        Random rng = new Random();
        int length = 10;
        String characters ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        char[] text = new char[length];
        for (int i = 0; i < length; i++)
        {
            text[i] = characters.charAt(rng.nextInt(characters.length()));
        }
        return new String(text);
    }

StringBuilderが最速で、+=最も遅い。参考までに!

0
Jam Hong