There is a corner case in String optimizations that is missing. It's a questionable programming practice, since the code sequence should just be replaced by "new String(s)", or even "s" assuming the new identity is not required. However, it might be trivial to support in OptimizeStringConcat?
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
public class ConcatSimpleBench {
@Param({"1", "64", "4096"})
int size;
private String s;
@Setup
public void setup() {
s = "";
for (int c = 0; c < size; c++) {
s += "a";
}
}
@Benchmark
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public String base() {
return new String(s);
}
@Benchmark
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public String sb() {
return new StringBuilder().append(s).toString();
}
}
Yields:
Benchmark (size) Mode Cnt Score Error Units
ConcatSimpleBench.base 1 avgt 15 4.971 �� 0.992 ns/op
ConcatSimpleBench.base 64 avgt 15 4.972 �� 1.044 ns/op
ConcatSimpleBench.base 4096 avgt 15 5.249 �� 1.045 ns/op
ConcatSimpleBench.sb 1 avgt 15 11.267 �� 2.628 ns/op
ConcatSimpleBench.sb 64 avgt 15 16.219 �� 0.296 ns/op
ConcatSimpleBench.sb 4096 avgt 15 814.078 �� 12.745 ns/op
"base" tests experiences constant-time performance (the char[] array is just shared). "sb" test experiences close to O(n), since it copies the backing char[] storage.