私のアプリケーションではすべて正常に動作していますが、パフォーマンスを向上させ、コードを最適化したいと考えています。
この2つのうちどちらが優れているか
1.初期化
String str1=new String("Hello");
String str2="Hello";
2.連結
System.out.println(s1 + s2);
System.out.println(new StringBuffer(S1).append(s2));
私のアプリケーションではすべて正常に動作していますが、パフォーマンスを向上させ、コードを最適化したいと考えています。
この2つのうちどちらが優れているか
1.初期化
String str1=new String("Hello");
String str2="Hello";
2.連結
System.out.println(s1 + s2);
System.out.println(new StringBuffer(S1).append(s2));
まず第一に、最初にアプリケーションのプロファイリングを行い、そうする非常に正当な理由を認識しない限り、パフォーマンスを向上させたり、コードを最適化したりしないでください。
第 2 に、String 変数の初期化では、String コンストラクターを使用しない方がよいでしょう。定数文字列を使用して (str2 で行ったように)、Java は String プールから String オブジェクトを引き出すことができます。
3 番目に、連結に StringBuffer を使用しないでください。代わりに StringBuilder を使用してください。StringBuffer のメソッドは同期されるため、アプリケーションの速度が大幅に低下します。実際、最新のコンパイラはすべて、「s1 + s2」のような式に StringBuilder を使用するバイト コードを作成するため、2 種類の連結はほぼ同じです。
System.out.println(s1 + s2);
System.out.println(new StringBuffer(S1).append(s2));
上記の2つから、最初は+
StringBuilderに変換されるため、StringBufferと比較して高速です。
とにかく...最速ですが、2つの文字列を追加するある種の厄介なstring1.concat(string2)
方法は、バッファのStringbuilderの新しいオブジェクトを生成する必要がないメソッドを使用することです。
sb.setLength(0)
各完全に追加された文字列の後にリセットすることにより、同じ StringBuilder を再利用して多くの文字列を追加することもできます
:
StringBuilder sb = new StringBuilder();
String done1 = sb.append("1").append("2").append("3").toString();
sb.setLength(0);
String done2 = sb.append("4").append("5").append("6").toString();
sb.setLength(0);
String done3 = sb.append("7").append("8").append("9").toString();
sb.setLength(0);
System.out.println(done1);
System.out.println(done2);
System.out.println(done3);
最後に、ループ内では、常に明示的に StringBuilder/Buffer を使用する必要があります。使用に関する魔法は無視して+
ください。ループの前に明示的に作成する必要があるオブジェクトは 1 つだけではなく、多くの一時的な StringBuilder オブジェクトになってしまうためです。
//not:
String result = "";
for (int i = 0; i < 20; i++) {
result += i; // this would create new StringBuilding in bytecode
}
System.out.println(result);
//but:
StringBuilder result1 = new StringBuilder();
for (int i = 0; i < 20; i++) {
result1.append(i);
}
System.out.println(result1);
のinitialization
String str2="Hello";
より良いアプローチです
のconcatenation
System.out.println(s1 + s2);
より良いアプローチです。
両方を使用String Constant pool
しているため、パフォーマンスを向上させることができます
初期化には、2 番目のバージョンを使用することをお勧めします。これは、JVM が文字列を「インターン」できるようにするためです。つまり、その定数が使用されるたびに、常に同じ文字列インスタンスを返すことができます。最初のバージョンでは、このコードが検出されると常に新しい String オブジェクトが作成されるため、余分なメモリ消費が発生します。
連結の場合、例のような単純なケースでは、コンパイラが最適化を行うため、両方の方法が本質的に同じになります。より複雑な文字列連結の場合は、Stringbuffer または StringBuilder を使用することをお勧めします。複数のスレッドから StringBuilder にアクセスする場合は、StringBuffer を使用する必要があります。それ以外の場合は、StringBuilder はロックを行わないため、パフォーマンスが向上します。
初期化では、オブジェクトを 1 つしか作成しないため、2 番目のアプローチが適しています。
文字列 str1=新しい文字列("こんにちは");
ここでは、2 つのオブジェクトが作成され、1 つはヒープに、もう 1 つは文字列プールに作成されます。
String str2="Hello";
ここでは、文字列プールに作成されるオブジェクトは 1 つだけです。
System.out.println(s1 + s2);
ここでは、合計 3 つのオブジェクトがあり、s1 s2 と s1+s2 がすべて文字列プールにあります。
System.out.println(新しい StringBuffer(S1).append(s2));
ここでは頭の領域にS1+S2のオブジェクトが 1 つしかないため、どちらの場合も 2 番目のアプローチが適しています。
初期化には、2 番目のアプローチの方が適しています。
String str2="Hello";
このようにして Java String Pool を利用し、不要な割り当てを回避できるからです。
連結の場合、多くの文字列連結を実行する必要がある場合は、2 番目の方法が最適です。2 つの文字列のみを連結するには、最初の方法の方が簡単で十分です...
使用する
String str2="Hello";
「Hello」文字列が JVM 文字列プールで使用可能な場合、新しいメモリ オブジェクトは作成されないため、文字列の初期化用
その他の 2 つの提案:
StringBuffer
ように各文字列操作で新しい文字列を作成しないため、を使用します。String
StringBuilder
は、マルチスレッド操作用に設計された StringBuffer の不要なオーバーヘッドを回避するために使用します。本当に必要になる前に最適化しないでください。
必要のないときに最適化すると、可読性が低下し、時間が無駄になります。文字列の初期化によってパフォーマンスの問題が発生することは非常にまれです。
1) リテラルを使用します。文字列リテラルは共通プールに格納されます。これにより、同じ内容の文字列のストレージを共有して、ストレージを節約できます。new 演算子によって割り当てられた文字列オブジェクトはヒープに格納され、同じ内容のストレージは共有されません。
以外
リテラルは、コンストラクターを使用するよりも読みやすいです。
2)StringBuilder
複数の文字列オブジェクトの作成を避ける + の代わりに for を使用します。
2 番目の点については、2 ~ 3 個の追加または + の場合、大きな違いはありません。
役立つかもしれません:
メモリ関連の問題のほとんどは、Java 自体によって維持/解決されます。大きな影響がない限り、クリーンで読みやすいコードを信じています。