Which one is better in terms of performance?
finalWords.stream().forEach(word -> stringBuilder.append(word).append(”,“));
String finalResult = stringBuilder.toString();
VS
String finalResult = finalWords.stream().collect(Collectors.joining(","));
It is always better to use StringBuilder. append to concatenate two string values. Let us cement this statement using the below micro benchmark.
String is immutable whereas StringBuffer and StringBuilder are mutable classes. StringBuffer is thread-safe and synchronized whereas StringBuilder is not. That's why StringBuilder is faster than StringBuffer. String concatenation operator (+) internally uses StringBuffer or StringBuilder class.
append(String str) method appends the specified string to this character sequence. The characters of the String argument are appended, in order, increasing the length of this sequence by the length of the argument.
Join is the fastest way of doing it. String. Join can look through all of the strings to work out the exact length it needs, then go again and copy all the data. This means there will be no extra copying involved.
I put together a small benchmark to test this out because I was curious. It initializes the List
with size
randomly-generated lowercase String
s, each having a length of 10
:
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(3)
public class MyBenchmark {
@Param({"10", "100", "1000", "10000", "100000"})
private int size;
private List<String> finalWords;
@Setup(Level.Invocation)
public void initialize() {
finalWords = IntStream.range(0, size)
.mapToObj(i -> {
return ThreadLocalRandom.current()
.ints(10, 'a', 'z' + 1)
.mapToObj(c -> Character.toString((char) c))
.collect(Collectors.joining());
}).collect(Collectors.toList());
}
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
@Benchmark
public String stringBuilder() {
StringBuilder sb = new StringBuilder();
finalWords.forEach(word -> sb.append(word).append(","));
return sb.toString();
}
@Benchmark
public String stream() {
return finalWords.stream().collect(Collectors.joining(","));
}
}
Here are the results:
Benchmark (size) Mode Cnt Score Error Units
MyBenchmark.stream 10 avgt 30 242.330 ± 5.177 ns/op
MyBenchmark.stream 100 avgt 30 1426.333 ± 20.183 ns/op
MyBenchmark.stream 1000 avgt 30 30779.509 ± 1114.992 ns/op
MyBenchmark.stream 10000 avgt 30 720944.424 ± 27845.997 ns/op
MyBenchmark.stream 100000 avgt 30 7701294.456 ± 648084.759 ns/op
MyBenchmark.stringBuilder 10 avgt 30 170.566 ± 1.833 ns/op
MyBenchmark.stringBuilder 100 avgt 30 1166.153 ± 21.162 ns/op
MyBenchmark.stringBuilder 1000 avgt 30 32374.567 ± 979.288 ns/op
MyBenchmark.stringBuilder 10000 avgt 30 473022.229 ± 8982.260 ns/op
MyBenchmark.stringBuilder 100000 avgt 30 4524267.849 ± 242801.008 ns/op
As you can see, the StringBuilder
method is faster in this case, even when I don't specify an initial capacity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With