web-dev-qa-db-ja.com

StringBuilder / StringBufferと「+」演算子の比較

私は(Better、Faster、Lighter Java)(Bruce TateとJustin Gehtlandによる)を読んでいて、アジャイルタイプチームの読みやすさの要件に精通しています。ロバート・マーティンが彼のきれいなコーディングの本で話しているようなものです。現在のチームでは、実行時に余分な(そして不要な)文字列オブジェクトを作成するため、_+_演算子を使用しないように明示的に指示されています。

しかし、これは article です。'04年に書き戻されたのは、オブジェクト割り当てが約10の機械語命令である方法についてです。 (基本的に無料)

また、GCがこの環境でのコスト削減にどのように役立つかについても説明します。

_+_、StringBuilder、またはStringBufferの使用間の実際のパフォーマンストレードオフは何ですか? (私の場合、Java 1.4.2に制限されているため、StringBufferのみです。)

StringBufferを使用すると、Tateの本にあるいくつかの例が示すように、コードが見にくく、読みにくくなります。そして、StringBufferはスレッド同期されます。これは、_+_演算子の使用における「危険」を上回る独自のコストがあるようです。

考え/意見?

35
avgvstvs

String連結の使用は、コンパイラーによってStringBuilder操作に変換されます。

コンパイラーの動作を確認するには、サンプルクラスを使用して、それをコンパイルし、jadで逆コンパイルして、生成されたバイトコードを確認します。

元のクラス:

public void method1() {
    System.out.println("The answer is: " + 42);
}

public void method2(int value) {
    System.out.println("The answer is: " + value);
}

public void method3(int value) {
    String a = "The answer is: " + value;
    System.out.println(a + " what is the question ?");
}

逆コンパイルされたクラス:

public void method1()
{
    System.out.println("The answer is: 42");
}

public void method2(int value)
{
    System.out.println((new StringBuilder("The answer is: ")).append(value).toString());
}

public void method3(int value)
{
    String a = (new StringBuilder("The answer is: ")).append(value).toString();
    System.out.println((new StringBuilder(String.valueOf(a))).append(" what is the question ?").toString());
}
  • オン method1コンパイラはコンパイル時に操作を実行しました。
  • オン method2String連結は、手動でStringBuilderを使用するのと同じです。
  • オン method3String連結は、コンパイラが前のものを再利用するのではなく、2番目のStringBuilderを作成しているため、明らかに悪いです。

したがって、私の単純なルールは、たとえばループで、または中間結果を格納する必要がある場合など、結果を再度連結する必要がない限り、連結は適切であることです。

49
gabuzo

チームは 繰り返し文字列連結を回避する理由 について学ぶ必要があります。

StringBufferを使用することが理にかなっている場合areは確かにあります-特にループで文字列を作成している場合は特にループの反復回数が少ないことはわかりません。新しいオブジェクトを作成するだけの問題ではないことに注意してください。既に追加したすべてのテキストデータをコピーするだけです。また、ガベージコレクションを考慮しない場合、オブジェクトの割り当ては「本質的に無料」であることに注意してください。はい、現在の世代に十分なスペースがある場合、それは基本的にポインターをインクリメントすることの問題です...しかし:

  • そのメモリは、ある時点でクリアされている必要があります。それは無料ではありません。
  • 次のGCが必要になるまでの時間を短縮しています。 GCは無料ではありません。
  • オブジェクトが次世代に存在する場合、クリーンアップに時間がかかる可能性があります。これも無料ではありません。

これらのすべてはかなり安く、オブジェクトの作成を避けるためにエレガンスから離れてデザインを曲げる価値はありません...しかし、あなたはすべきではありませんfreeと見なします。

一方、中間の文字列が必要ない場合は、StringBufferを使用しても意味がありません。例えば:

String x = a + b + c + d;

少なくとも以下と同じくらい効率的です:

StringBuffer buffer = new StringBuffer();
buffer.append(a);
buffer.append(b);
buffer.append(c);
buffer.append(d);
String x = buffer.toString();
24
Jon Skeet

小さな連結の場合、読みやすくするために文字列と+を使用できます。パフォーマンスが低下することはありません。ただし、多数の連結操作を行う場合は、StringBufferを使用します。

5
adrianboimvaser