StringがあるのになぜStringBuilderなのですか?


82

StringBuilderは初めて遭遇しましたが、JavaにはすでにString追加できる非常に強力なクラスがあるので、驚きました。

なぜセカンドStringクラス?

どこでもっと知ることができStringBuilderますか?



これが実際に私へのインタビューの質問として一度出てきたことに注意したかっただけです。彼らは.....大きな文字列を移入するために私は尋ねただろう
preOtep

回答:


171

String追加は許可されません。で呼び出す各メソッドStringは、新しいオブジェクトを作成して返します。これは、Stringが不変であるためです。内部状態を変更することはできません。

一方、StringBuilder変更可能です。呼び出すappend(..)と、新しい文字列オブジェクトを作成するのではなく、内部のchar配列を変更します。

したがって、次のようにする方が効率的です。

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 500; i ++) {
    sb.append(i);
}

ではなく、str += i500個の新しい文字列オブジェクトを作成します。

この例では、ループを使用していることに注意してください。heliosがコメントで指摘しているように、コンパイラーString d = a + b + cは次のような式を自動的に次のように変換します。

String d = new StringBuilder(a).append(b).append(c).toString();

StringBufferに加えてがあることにも注意してくださいStringBuilder。違いは、前者には同期されたメソッドがあることです。ローカル変数として使用する場合は、を使用してくださいStringBuilder。複数のスレッドからアクセスされる可能性がある場合は、を使用してくださいStringBuffer(まれです)


24
+1。次のように追加できます。「したがって、StrungBuilderはパフォーマンスを探します」および「Javaコンパイラは、オブジェクト作成のパフォーマンスを回避するために、A + B + Cなどの式を新しいStringBuilder(A).append(B).append(C).toString()に置き換えます。ペナルティ」:)
helios 2011年

そして、みなさん、どうもありがとうございました。あなたはすべて+1に値します(これはすぐに配信されます:)
an00b 2011年

「不変」オブジェクトのリコールのようなものです。
Gary Tsui

素晴らしい反応。しかし、私が見逃しているのは、forループを含め、ほとんどの場合Stringbuilderをいつ使用するかをコンパイラーに判断させることができないため、開発者として考える必要がない理由です。:)
worldsayshi 2015

いい答えだ 。これらの行を追加したいと思います。文字列を保持する配列(つまりchar []値)はfinalとして宣言されるため、文字列は不変ですが、StringBuilderの場合、文字列を保持する配列(つまりchar []値)はfinalではありません。Stringbuilderの場合は文字列を保持する配列に変更を加えることができます
Deen John

60

これが理由の具体例です-

int total = 50000;
String s = ""; 
for (int i = 0; i < total; i++) { s += String.valueOf(i); } 
// 4828ms

StringBuilder sb = new StringBuilder(); 
for (int i = 0; i < total; i++) { sb.append(String.valueOf(i)); } 
// 4ms

ご覧のとおり、パフォーマンスの違いは重要です。


追伸 これをMacbookProDualコアで実行しました。
アミールラミンファー2011年

これは理由を説明していません
Steve Kuo 2011年

25
これは、StringがあるのになぜStringBuilderなのかを説明していますか?これは、StringBuilderが非常に高速である理由を説明していませんしかし、それは問題ではありません。したがって、これは有効な答えです。
ケレムBaydoğan

2
@ krmby-同意しました。なぜ答えるのは本当に別の質問のためのものです。
アミールラミンファー2011年

12
比較を公平にするs = sb.ToString();ために、最後にaを実行する時間を含める必要があると思います。そうすれば、少なくとも両方の例で同じことを実行できます(結果はaですstring)。
スコットホイットロック2012

19

Stringクラスは不変ですが、StringBuilderは変更可能です。

String s = "Hello";
s = s + "World";

Stringは不変であるため、上記のコードは2つのオブジェクトを作成します

StringBuilder sb = new StringBuilder("Hello");
sb.append("World");

StringBuilderは不変ではないため、上記のコードでは1つのオブジェクトのみが作成されます。

レッスン:文字列を何度も操作/更新/追加する必要があるときはいつでも、文字列と比較して効率的であるとしてStringBuilderを選択してください。


8

StringBuilderは、文字列を作成するためのものです。具体的には、非常にパフォーマンスの高い方法でそれらを構築します。Stringクラスは多くの点で優れていますが、新しい文字列はまったく新しい再割り当てされた文字列であるため、小さな文字列部分から新しい文字列を組み立てる場合、実際には非常に優れたパフォーマンスを発揮します。(不変です)StringBuilderは同じシーケンスを所定の位置に保持し、それを変更します(可変)。


5

StringBuilderクラスは変更可能であり、Stringとは異なり、Stringオブジェクトをさらに作成しなくても文字列の内容を変更できます。これにより、文字列を大幅に変更するときにパフォーマンスが向上する可能性があります。StringBufferと呼ばれるStringBuilderに対応するものもあり、これも同期されるため、マルチスレッド環境に最適です。

Stringの最大の問題は、Stringを使用して実行すると、常に新しいオブジェクトが返されることです。

String s1 = "something";
String s2 = "else";
String s3 = s1 + s2; // this is creating a new object.

4

StringBuilderは、より大きな文字列を扱う場合に適しています。パフォーマンスの向上に役立ちます。

これが私が役に立ったと思った記事です。

クイックグーグル検索はあなたを助けたかもしれません。今あなたはあなたのためにグーグル検索をするために7人の異なる人々を雇いました。:)


私たちは皆、ここで無給の仕事をしていませんか?
デッドプール

4

正確には、すべての文字列を追加するStringBuilderはO(N)であり、文字列の追加はO(N ^ 2)です。ソースコードをチェックすると、これは文字の可変配列を保持することによって内部的に達成されます。StringBuilderは、配列の長さの複製手法を使用して、必要なメモリを2倍にする可能性を犠牲にして、償却されたO(N ^ 2)パフォーマンスを実現します。これを解決するために最後にtrimToSizeを呼び出すことができますが、通常、StringBuilderオブジェクトは一時的にのみ使用されます。最終的な文字列サイズで適切な開始推測を提供することにより、パフォーマンスをさらに向上させることができます。


3

効率。

文字列を連結するたびに、新しい文字列が作成されます。例えば:

String out = "a" + "b" + "c";

これにより、新しい一時的な文字列が作成され、「a」と「b」がコピーされて「ab」になります。次に、別の新しい一時文字列を作成し、それに「ab」と「c」をコピーして、「abc」にします。次に、この結果はに割り当てられoutます。

結果は、O(n²)(二次)時間計算量の画家のアルゴリズムであるSchlemielです。

StringBuilder一方、文字列をインプレースで追加し、必要に応じて出力文字列のサイズを変更できます。


多くのJVM実装は、例をStringBuilderにコンパイルしてから、最終結果をStringに変換します。このような場合、文字列の割り当てを繰り返してもアセンブルされません。
scottb 2013

1

JavaにはString、StringBuffer、StringBuilderがあります。

  • 文字列:その不変

  • StringBuffer:その可変でスレッドセーフ

  • StringBuilder:Java 1.5で導入された、変更可能であるがスレッドセーフではない

文字列例:

public class T1 {

    public static void main(String[] args){

        String s = "Hello";

        for (int i=0;i<10;i++) {

            s = s+"a";
            System.out.println(s);
        }
    }
}

}

出力:1つの文字列ではなく、10の異なる文字列が作成されます。

Helloa
Helloaa
Helloaaa
Helloaaaa
Helloaaaaa
Helloaaaaaa
Helloaaaaaaa
Helloaaaaaaaa 
Helloaaaaaaaaa 
Helloaaaaaaaaaa

StringBuilder例:1つのStringBuilderオブジェクトのみが作成されます。

public class T1 {

    public static void main(String[] args){

        StringBuilder s = new StringBuilder("Hello");

        for (int i=0;i<10;i++) {    
            s.append("a");
            System.out.println(s);
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.