join String array Java

Join string array in Java - performance

One of the most common programmatic tasks in Java is to join String array to a single String. It might be useful for logging an array content, or to build an SQL query, or for many more reasons. The point is - there is no single convenient solution supported by the language, but there are many options to concatenate multiple Strings into one. In this post, I will show you a few such options and I will execute simple performance tests to compare their efficiencies.

 

Join manually with StringBuilder

That is probably the first choice for everybody that does not know any specific method. We can iterate over the array elements and append them to the StringBuilder instance.

private String stringBuilder(String[] array) {
StringBuilder builder = new StringBuilder();
for (String s: array) {
builder.append(s).append(",");
}
builder.deleteCharAt(builder.length() - 1);
return builder.toString();
}

Of course, the separator must be added after each item except the last one. In this implementation I avoid checking an IF statement in each iteration. I just remove the last character at the end.

 

String.join method

Those that do not want to waste their time on writing so much code, there is a dedicated static method in String class - join. It is available since Java 1.8, so it has been there for a long time.

private String stringJoin(String[] array) {
return String.join(",", array);
}

The implementation is very simple. The String.join method needs two arguments: a separator and an array.

 

StringJoiner

Java 1.8 made us happy in many different ways. For the first time appeared StringJoiner class. Yes, a dedicated class to just join Strings from an array.

private String stringJoiner(String[] array) {
StringJoiner joiner = new StringJoiner(",");
for (String s : array) {
joiner.add(s);
}
return joiner.toString();
}

That is not so convenient to use it with an array of Strings, because we still need to iterate over the elements ourselves, but it is still a valid option. You may also try using StringJoiner with a Java Stream to avoid an explicit for loop.

 

Stream Collector

As we speak about Java Streams in Java 1.8, Strings can be joined using a Stream of elements collected by joining them.

private String streamCollector(String[] array) {
return Arrays.stream(array).collect(Collectors.joining(","));
}

The array must be converted to a Stream first, but the rest is easy. The elements can be collected using a Joining Collector.

By the way, do you know how to convert a list to a map with Java Streams?

 

Guava Joiner

Do you think that it is enough of native Java methods to join String array? Maybe. There are also 3rd party libraries that can help with that. One of them is Guava:

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>

It provide a special Joiner class.

private String guavaJoiner(String[] array) {
return Joiner.on(",").join(array);
}

It is initialized by calling the static on method with a separator, then the join method allows providing an array and does the joining.

Do not miss valuable content. You will receive a monthly summary email. You can unsubscribe anytime.

Apache Commons

Another worth mention 3rd party library is Apache Commons.

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>

It provide a utility class for a bunch of String operations like joining array elements to a String with a separator.

private String apacheCommons(String[] array) {
return StringUtils.join(array, ",");
}

The static join method gets an array and a separator and does the rest.

 

Performance test set up

As you already know the possible solutions, let's see how they will be tested.

I prepared a test class with an array of String elements. There is a test method called testPerformance(). It measures a time duration and prints it to the console.

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class PerformanceTest {

private static final int NUM_OF_ELEMENTS = 10000;
private String[] array;

@BeforeEach
void setUp() {
array = new String[NUM_OF_ELEMENTS];
for (int i = 0; i < NUM_OF_ELEMENTS; i++) {
array[i] = String.valueOf(i);
}
}
   @Test
void testPerformance() {
long startTime = System.currentTimeMillis();

// execute the method here
String result = stringBuilder(array);
// String result = stringJoin(array);
// String result = stringJoiner(array);
// String result = streamCollector(array);
// String result = guavaJoiner(array);
// String result = apacheCommons(array);

System.out.println("Took " + (System.currentTimeMillis() - startTime) + " ms.");
System.out.println(result);
}

}

The testPerformance method contains execution of all the methods described above. Currently, only one is uncommented and will be executed. Subsequently, I will repeat the test for each method separately focusing on the time duration printed to the console. To make it quasi-professional, I will run each method 3 times, exclude the extreme values (the lowest and the greatest) and I will use the middle one as a result.

 

Performance test result

The table below contains these middle durations for each method.

Method name Duration [ms]
stringBuilder 2
stringJoin 10
stringJoiner 9
streamCollector 9
guavaJoiner 11
apacheCommons 19

 

Surprisingly, at least for me, the fastest method was using a StringBuilder with quite a big difference. Apache Commons appeared to be twice slow than average.

Mind that the test scenario contains joining only once a long array of Strings. The results might be different if the array were much shorter. Feel free to perform such a test if you want. This post contains all the necessary code.

Additionally, speed is not always the only factor. Memory usage is also important in many cases. This test did not measure that. You should craft a test to your specific needs if you need to find the best method in your case, not a good-enough one.

If you like what I do, consider buying me a coffee :)

Buy me a coffeeBuy me a coffee