I am considering sending RFE (request for promotion) to the Oracle Bug database, which should significantly increase string concatenation performance. But before I do this, I would like to hear expert comments about whether it makes sense.
The idea is based on the fact that the existing String.concat (String) is twice as fast on 2 lines than StringBuilder. The problem is that there is no way to concatenate 3 or more lines. External methods cannot do this because String.concat uses the private package constructor String(int offset, int count, char[] value) , which does not copy the char array, but uses it directly. This provides String.concat high performance. Being in the same package, StringBuilder still cannot use this constructor because the String char array will be displayed for modifications.
I suggest adding the following methods to 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)
Note: this type of overload is used in EnumSet.of for efficiency.
This is an implementation of one of the methods, others work the same way.
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); }
Also, after adding these methods to String, the Java compiler for
String s = s1 + s2 + s3;
will be able to create effective
String s = String.concat(s1, s2, s3);
instead of the current ineffective
String s = (new StringBuilder(String.valueOf(s1))).append(s2).append(s3).toString();
UPDATE Performance Test. I ran it on my Intel Celeron 925 laptop, combining 3 lines, my String2 class emulates exactly how it will be in real java.lang.String. String lengths are chosen so that the StringBuilder is in the most adverse conditions, that is, when it needs to expand its internal buffer capacity on each addition, while concat always creates char [] only once.
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); } }
at 1,000,000 iterations results:
version 1 = ~200 ms version 2 = ~400 ms