文字列連結のパフォーマンスを大幅に向上させると思われるRFE(拡張要求)をOracleBugDatabaseに送信することを検討しています。しかし、それを行う前に、それが理にかなっているかどうかについての専門家のコメントを聞きたいと思います。
このアイデアは、既存のString.concat(String)がStringBuilderよりも2つの文字列で2倍高速に動作するという事実に基づいています。問題は、3つ以上の文字列を連結する方法がないことです。String(int offset, int count, char[] value)
String.concatは、char配列をコピーせずに直接使用するパッケージプライベートコンストラクターを使用するため、外部メソッドはこれを実行できません。これにより、String.concatの高いパフォーマンスが保証されます。同じパッケージ内にある場合でも、StringBuilderはこのコンストラクターを使用できません。これは、Stringのchar配列が変更のために公開されるためです。
次のメソッドをStringに追加することをお勧めします
public static String concat(String s1, String s2)
public static String concat(String s1, String s2, String s3)
public static String concat(String s1, String s2, String s3, String s4)
public static String concat(String s1, String s2, String s3, String s4, String s5)
public static String concat(String s1, String... array)
注:この種のオーバーロードは、効率を上げるためにEnumSet.ofで使用されます。
これは、メソッドの1つの実装であり、他のメソッドは同じように機能します
public final class String {
private final char value[];
private final int count;
private final int offset;
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public static String concat(String s1, String s2, String s3) {
char buf[] = new char[s1.count + s2.count + s3.count];
System.arraycopy(s1.value, s1.offset, buf, 0, s1.count);
System.arraycopy(s2.value, s2.offset, buf, s1.count, s2.count);
System.arraycopy(s3.value, s3.offset, buf, s1.count + s2.count, s3.count);
return new String(0, buf.length, buf);
}
また、これらのメソッドがStringに追加された後、Javaコンパイラは
String s = s1 + s2 + s3;
効率的に構築できるようになります
String s = String.concat(s1, s2, s3);
現在の非効率の代わりに
String s = (new StringBuilder(String.valueOf(s1))).append(s2).append(s3).toString();
UPDATEパフォーマンステスト。私はそれをノートブックのIntelCeleron925で実行し、3つの文字列を連結しました。私のString2クラスは、実際のjava.lang.Stringでの動作を正確にエミュレートします。文字列の長さは、StringBuilderを最も不利な条件に置くように選択されます。つまり、各追加で内部バッファ容量を拡張する必要がある場合ですが、concatは常にchar[]を1回だけ作成します。
public class String2 {
private final char value[];
private final int count;
private final int offset;
String2(String s) {
value = s.toCharArray();
offset = 0;
count = value.length;
}
String2(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
public static String2 concat(String2 s1, String2 s2, String2 s3) {
char buf[] = new char[s1.count + s2.count + s3.count];
System.arraycopy(s1.value, s1.offset, buf, 0, s1.count);
System.arraycopy(s2.value, s2.offset, buf, s1.count, s2.count);
System.arraycopy(s3.value, s3.offset, buf, s1.count + s2.count, s3.count);
return new String2(0, buf.length, buf);
}
public static void main(String[] args) {
String s1 = "1";
String s2 = "11111111111111111";
String s3 = "11111111111111111111111111111111111111111";
String2 s21 = new String2(s1);
String2 s22 = new String2(s2);
String2 s23 = new String2(s3);
long t0 = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
String2 s = String2.concat(s21, s22, s23);
// String s = new StringBuilder(s1).append(s2).append(s3).toString();
}
System.out.println(System.currentTimeMillis() - t0);
}
}
1,000,000回の反復で、結果は次のようになります。
version 1 = ~200 ms
version 2 = ~400 ms