ベストプラクティス/パフォーマンス:StringBuilder.appendとString.concatの混合


86

私は、ベストプラクティスとは何か、そしてさまざまなケースで文字列リテラルと変数を連結する理由を理解しようとしています。たとえば、私がこのようなコードを持っている場合

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

これはそれを行う方法ですか?この投稿から+、Stringsの演算子がStringBuilderの新しいインスタンスを作成し、オペランドを連結し、String変換を返すことに気付きました。これは、単に呼び出すよりもはるかに多くの作業のよう.append()です。それが本当なら、それは問題外です。しかし、どうString.concat()ですか?.append()すべての連結に使用するのは適切ですか?または、変数の場合、リテラルに追加してもかまい.concat()ませんか?

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

これらの状況を回避するためのベストプラクティスとパフォーマンスの一般的なルールは何ですか?私の仮定は正しい+ですか、それは本当に使用されるべきではありませんか?


基本的にあなたはそれを持っていると思います。String +「本当に使用すべきではない」かどうかについては意見が異なります。重要なのは、結果を理解しているということです
ControlAltDel 2012

回答:


184

+ オペレーター

String s = s1 + s2

舞台裏では、これは次のように翻訳されます。

String s = new StringBuilder(s1).append(s2).toString();

s1 + s2ここにある場合、追加の作業量を想像してみてください。

stringBuilder.append(s1 + s2)

の代わりに:

stringBuilder.append(s1).append(s2)

複数の文字列 +

注意する価値がある:

String s = s1 + s2 + s3 + ... +sN

に翻訳されます:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

Stringとのchar[]両方に適合する配列を作成します。コピーとs1s2s1s2この新しいアレイへのコンテンツ。実際には、+オペレーターよりも少ない作業で済みます。

StringBuilder.append()

char[]必要に応じて拡張する内部配列を維持します。余分なものはありませんchar[]内部のものが十分に大きい場合、は作成され。

stringBuilder.append(s1.concat(s2))

またs1.concat(s2)、余分なchar[]配列を作成してコピーしs1s2、それにだけ内部にその新しい配列の内容をコピーしますStringBuilder char[]

そうは言ってappend()も、常に使用し、生の文字列を追加する必要があります(最初のコードスニペットは正しいです)。


あなたの助けと詳細な説明に感謝します。それが私が本当に必要としていたものです。
Nick Rolando 2012

12
コンパイラの新しいバージョンでは、+演算子が文字列ビルダーに自動的に最適化されますが、古いバージョンではそうではないので、そうなると想定するのは必ずしも良いことではありません。この議論全体で無視されている非常に重要なトピックがあります。これは、実際には文字列プールであるStringBuilderの主な目的の1つです。文字列ビルダーを使用すると、すべてがchar []として保持され、コンパイラーの最適化の前に+演算子が行ったように中間文字列が作成されません(単に連結を行うために使用されます)。concatを使用すると、キャッシュされているが使用されていない中間のStringオブジェクトが作成されます。
LINEMAN78 2012

したがって、1回限りのステートメント(メソッド全体で複数のステートメントではない)を複数の異なる文字列で連結している場合。基本的に同じことをするので、この1回限りの連結+を作成する代わりに、Stringオブジェクトで使用しても問題ありStringBuilderませんか?
Nick Rolando 2012

1
また、文字のみを連結したい場合は、.append( "\ n")の代わりに.append( '\ n')を使用する方がよいでしょうか。文字はプリミティブ型であり、文字列はオブジェクトなのでしょうか?
vrwim 2013年

3
効果的なJava第2版文字列連結演算子を繰り返し使用してn個の文字列を連結するには、nの2次時間が必要です。それで、それはまだ関連していますか?
gkiko 2015年

16

コンパイラは+連結を最適化します。

そう

int a = 1;
String s = "Hello " + a;

に変換されます

new StringBuilder().append("Hello ").append(1).toString();

+演算子を使用する理由を説明する優れたトピックがここにあります。


3
String s = "Hello World";リテラルを使用するため、コンパイラは実際にそれを最適化します。
ColinD 2012

@ColinD:+1。スニペットを変更しました。

3

最適化はコンパイラーによって自動的に行われます。

Java2コンパイラは、以下を自動的に変換します。

String s = s1 + s2; 

String s = (new StringBuffer()).append(s1).append(s2).toString();

OracleのWebサイトのJavaベストプラクティスから直接引用。


2

常に使用する必要があります append

concat 新しい文字列を作成して、次のようにします。 +私が思うになります。

concatまたは+2つの最終文字列で使用する場合、JVMは最適化を行うことができるため、この場合の追加を行うのと同じです。


1

正確に2つの文字列を連結する場合は、String.concatを使用します(両方の文字列に適合する新しいchar配列を作成し、両方の文字列のchar配列をコピーして新しい文字列を作成します)。

1行に複数(3つ以上)の文字列を連結する場合は、+またはStringBuilder.appendを使用します。コンパイラは、+をStringBuilder.appendに変換するため、問題ありません。これは、必要に応じて大きくなる1つのchar配列を維持するため、複数の文字列に適しています。

複数の文字列を複数の行に連結する場合は、1つのStringBuilderを作成し、append-methodを使用します。最後に、StringBuilderへの文字列の追加が完了したら、その.toString()メソッドを使用して文字列を作成します。複数行で連結する場合、これは2番目の方法よりも高速です。2番目の方法では各行に新しいStringBuilderが作成され、文字列が追加されてからStringにキャストバックされますが、3番目の方法では全体で1つのStringBuilderのみが使用されます。


0

+演算子の使用はベストプラクティスであり、シンプルで読みやすいものでもあります。

Java言語は、文字列連結演算子(+)、および他のオブジェクトの文字列への変換を特別にサポートします。文字列の連結は、StringBuilder(またはStringBuffer)クラスとそのappendメソッドを介して実装されます。

公式文書:https//docs.oracle.com/javase/8/docs/api/java/lang/String.html


0

バイトコードレベルでは違いはなく、効率を損なうことはありません。バイトコードレベルを実行する場合は、appendを呼び出して、+の非インライン演算子オーバーロードメソッドを実行する必要があります。次に、アセンブリ言語レベルで(JavaはCで記述され、Cはアセンブリと同様のアセンブリを生成し、スタックに+メソッド呼び出しを格納するための追加のレジスタ呼び出しがあり、追加のプッシュがあります(実際には、クロスコンパイラが+演算子を最適化する場合があります)。その場合、効率との違いはありません。)

読みやすさを向上させる1つの方法があることをお勧めします。:)


0

私は個人的にStrings.format()、シンプルで読みやすい1行の文字列フォーマッタを好みます

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F

0

すべての答えはかなり良く、説明的です。しかし、Guava Joiner、Streams、String.formatなど、他の文字列連結手法の調査も役立つと感じました。

各連結手法のパフォーマンスの詳細については、java-string-concatenation-which-way-is-bestを参照してください

簡単に言うと、連結のパフォーマンスは違います。連結する文字列の数。たとえば、1〜10個の文字列を連結するには、これらの手法が最適です-StringBuilder、StringBuffer、およびPlusOperator。そして、何百もの文字列を連結するために-Guava Joiner、apacheのstringsUtilsライブラリもうまく機能します。

上記のブログをご覧ください。それは本当にパフォーマンス効率を非常によく説明します。

ありがとう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.