I was looking at the performance of StringCharBuffer for various
backing CharSequence types and was surprised to see a significant
performance difference between String and StringBuffer. I wrote a
small jmh which shows that the String implementation of charAt is
significantly slower than StringBuilder. Is this expected?

Benchmark                            (data)      (source)  Mode  Cnt
  Score       Error  Units
CharSequenceCharAtBenchmark.test      ascii        String  avgt    3
2537.311 ┬▒  8952.197  ns/op
CharSequenceCharAtBenchmark.test      ascii  StringBuffer  avgt    3
852.004 ┬▒  2532.958  ns/op
CharSequenceCharAtBenchmark.test  non-ascii        String  avgt    3
5115.381 ┬▒ 13822.592  ns/op
CharSequenceCharAtBenchmark.test  non-ascii  StringBuffer  avgt    3
836.230 ┬▒  1154.191  ns/op



@Measurement(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS)
@Warmup(iterations = 2, time = 7, timeUnit = TimeUnit.SECONDS)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Fork(value = 1, jvmArgsPrepend = {"-Xms512M", "-Xmx512M"})
public class CharSequenceCharAtBenchmark {

    @Param(value = {"ascii", "non-ascii"})
    public String data;

    @Param(value = {"String", "StringBuffer"})
    public String source;

    private CharSequence sequence;

    @Setup(Level.Trial)
    public void setup() throws Exception {
        StringBuilder sb = new StringBuilder(3152);
        for (int i=0; i<3152; ++i) {
            char c = (char) i;
            if ("ascii".equals(data)) {
                c = (char) (i & 0x7f);
            }
            sb.append(c);
        }

        switch(source) {
            case "String":
                sequence = sb.toString();
                break;
            case "StringBuffer":
                sequence = sb;
                break;
            default:
                throw new IllegalArgumentException(source);
        }
    }

    @Benchmark
    public int test() {
        int sum = 0;
        for (int i=0, j=sequence.length(); i<j; ++i) {
            sum += sequence.charAt(i);
        }
        return sum;
    }
}

Reply via email to