@BenchmarkMode(Mode.Throughput) @Fork(1) @State(Scope.Thread) @Warmup(iterations = 10, time = 1, batchSize = 1000) @Measurement(iterations = 40, time = 1, batchSize = 1000) public class Chaining { private String a1 = "111111111111111111111111"; private String a2 = "222222222222222222222222"; private String a3 = "333333333333333333333333"; @Benchmark public String typicalChaining() { return new StringBuilder().append(a1).append(a2).append(a3).toString(); } @Benchmark public String noChaining() { StringBuilder sb = new StringBuilder(); sb.append(a1); sb.append(a2); sb.append(a3); return sb.toString(); } }
Benchmark Mode Cnt Score Error Units Chaining.noChaining thrpt 40 8408.703 ± 214.582 ops/s Chaining.typicalChaining thrpt 40 35830.907 ± 1277.455 ops/s
sb.append().append()
call chain is 4 times faster ... The author from the article above states that the difference is due to the fact that in the case of the call chain less bytecode is generated and, accordingly, it runs faster.
public class UriBuilder { private String schema; private String host; private String path; public UriBuilder setSchema(String schema) { this.schema = schema; return this; } ... @Override public String toString() { return schema + "://" + host + path; } }
@BenchmarkMode(Mode.Throughput) @Fork(1) @State(Scope.Thread) @Warmup(iterations = 10, time = 1, batchSize = 1000) @Measurement(iterations = 40, time = 1, batchSize = 1000) public class UriBuilderChaining { private String host = "host"; private String schema = "http"; private String path = "/123/123/123"; @Benchmark public String chaining() { return new UriBuilder().setSchema(schema).setHost(host).setPath(path).toString(); } @Benchmark public String noChaining() { UriBuilder uriBuilder = new UriBuilder(); uriBuilder.setSchema(schema); uriBuilder.setHost(host); uriBuilder.setPath(path); return uriBuilder.toString(); } }
Benchmark Mode Cnt Score Error Units UriBuilderChaining.chaining thrpt 40 35797.519 ± 2051.165 ops/s UriBuilderChaining.noChaining thrpt 40 36080.534 ± 1962.470 ops/s
StringBuilder
and append()
, then this is probably due to the well-known JVM option +XX:OptimizeStringConcat
. Let's check. Repeat the very first test, but with the option disabled.
@Fork(value = 1, jvmArgsAppend = "-XX:-OptimizeStringConcat")
Benchmark Mode Cnt Score Error Units Chaining.noChaining thrpt 40 7598.743 ± 554.192 ops/s Chaining.typicalChaining thrpt 40 7946.422 ± 313.967 ops/s
x + y
quite a frequent operation in any application - the Hotspot JVM finds new StringBuilder().append(x).append(y).toString()
patterns in bytecode and replaces them with optimized machine code , without creating intermediate objects.
sb.append(x); sb.append(y);
sb.append(x); sb.append(y);
. The difference on large lines can be on the order.
StringBuilder
this will help the JIT to optimize string concatenation. Secondly, less bytes of code are generated this way and it can really help to inline your method in some cases.
Source: https://habr.com/ru/post/330220/