In this article we are sharing the program to identify which is the best performance provider out of StringJoiner, StringBuffer, StringBuilder and Collectors.joining() while joining/appending String.
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;
public class PerformanceTest {
public static void main(String[] args) {
List<String> l = new ArrayList<>();
for(int i=0;i<1000;i++) {
l.add("12345"+i);
}
long start = System.currentTimeMillis();
usingStringJoiner(l);
long middle = System.currentTimeMillis();
System.out.println("Time taken by StringJoiner : "+(middle - start));
usingStringBuffer(l);
long end = System.currentTimeMillis();
System.out.println("Time taken by StringBuffer : "+(end-middle));
usingCollectors(l);
long end1 = System.currentTimeMillis();
System.out.println("Time taken by Collectors.joining() : "+(end1 - end));
usingStringBuilder(l);
System.out.println("Time taken by StringBuilder : "+(System.currentTimeMillis() - end1));
}
private static void usingStringJoiner(List<String> list) {
StringJoiner sj = new StringJoiner("|");
list.stream().filter(code -> code != null).forEach(code -> sj.add(code));
String s = sj.toString();
System.out.println(s);
}
private static void usingStringBuffer(List<String> list) {
StringBuffer buf = new StringBuffer();
list.stream().forEach(code -> buf.append(code).append("|"));
String output = buf.toString();
if (output.endsWith("|")) {
output = output.substring(0, output.length() - 1);
}
System.out.println(output);
}
private static void usingCollectors(List<String> list) {
String str = list.stream().collect(Collectors.joining("|"));
System.out.println(str);
}
private static void usingStringBuilder(List<String> list) {
StringBuilder builder = new StringBuilder();
list.stream().forEach(code -> builder.append(code).append("|"));
String output = builder.toString();
if (output.endsWith("|")) {
output = output.substring(0, output.length() - 1);
}
System.out.println(output);
}
}
Time taken by StringJoiner : 49
Time taken by StringBuffer : 2
Time taken by Collectors.joining() : 4
Time taken by StringBuilder : 3
If you observe the above statistics of StringJoiner and Collectors.joining(), StringJoiners are taking 49 milliseconds to complete the task where Collectors.joining() is taking only 4 milliseconds which is 45 milliseconds lesser. Here one point I would like to bring to your notice is, StringJoiner is used in the implementation of joining() in Collections. But, when I use StringJoiner externally, it is taking more time than how joining() performing.
public static Collector<CharSequence, ?, String> joining( CharSequence delimiter, CharSequence prefix, CharSequence suffix) { return new CollectorImpl<>( () -> new StringJoiner(delimiter, prefix, suffix), StringJoiner::add, StringJoiner::merge, StringJoiner::toString, CH_NOID); }
StringJoiner internally uses StringBuilder to store value.
/* * StringBuilder value -- at any time, the characters constructed from the * prefix, the added element separated by the delimiter, but without the * suffix, so that we can more easily add elements without having to jigger * the suffix each time. */ private StringBuilder value; /* preparing StringBuiler object in StringJoiner */ private StringBuilder prepareBuilder() { if (value != null) { value.append(delimiter); } else { value = new StringBuilder().append(prefix); } return value; }
StringBuilder has been used across all the methods of StringJoiner to perform various operations. There is one more option of using StringUtils.join() method to perform similar operation. I would like to suggest to use StringBuffer than StringUtils because it internally uses the StringBuffer only to store value.