Objective
Java 8 introduced a class called StringJoiner. It is a simple class which we can use to build a sequence of characters that are separated by a configured delimiter. It also supports optional prefix and suffix, which when provided would be the prefix and suffix of the concatenated string (with the delimiter). In this post we will learn about the Java 8 StringJoiner class with examples.
StringJoiner constructors
There are two constructors in the Java 8 StringJoiner class.
- A StringJoiner with a delimiter
- A StringJoiner with a delimiter, prefix, and suffix
StringJoiner with a delimiter
The most basic way to construct a StringJoiner instance is to just pass the delimiter (a String) using which to concatenate the multiple CharSequences that will be added later to the StringJoiner. The built string will not have any prefix or suffix.
StringJoiner with a delimiter, prefix, and suffix
We pass the delimiter, prefix and a suffix (all are Strings) to this version of the StringJoiner. The final built String will begin with the passed prefix and end with the suffix and has the individual characters/strings passed separated by the delimiter.
The Java 8 StringJoiner methods
Let us have a brief look at the methods in the Java 8 StringJoiner class. Do not worry if you don’t understand them. We will look at each of them with examples.
add
The add method takes a CharSequence and copies it as the next value of the StringJoiner. If passed a null, “null” will be added.
toString
This method is used to get the current value of the StringJoiner as a string. It returns:
prefix + {the values joined by the delimiter} + suffix
If no values are added, it returns the concatenation of prefix and suffix alone.
length
The length method returns the length of string representation of the StringJoiner (as per the toString method).
setEmptyValue
This sets a special sequence of characters to be used when no values are added to the StringJoiner i.e., when it is empty. Note that even if we add an empty string to the StringJoiner, the StringJoiner will be considered as non-empty.
merge
The merge method takes another StringJoiner and adds the contents of that StringJoiner without prefix and suffix as the next element to this StringJoiner (the StringJoiner on which the merge method is called).
Basic StringJoiner with delimiter
Let us look at how to use a basic StringJoiner which we have configured to use a delimiter only (no prefix, suffix).
Adding Strings to a StringJoiner
We build a StringJoiner instance by passing the delimiter as hyphen. Then we add three strings to it. Internally, it would mutate the StringJoiner instance each time we add a string.
StringJoiner stringJoiner = new StringJoiner("-");
stringJoiner.add("John");
stringJoiner.add("Michael");
stringJoiner.add("Kent");
System.out.println(stringJoiner.toString()); //John-Michael-Kent
System.out.println(stringJoiner.length()); //17
Calling toString returns the built string which is the individual String values passed concatenated by the delimiter.
The length method returns the length of the string that the toString method will return.
Most of the StringJoiner methods like add, merge returns the same instance of the StringJoiner (this). Hence we can chain the calls on it like,
StringJoiner stringJoiner = new StringJoiner("-")
.add("John")
.add("Michael")
.add("Kent");
Adding only one element
The below example demonstrates adding only one value. In this case, the delimiter cannot be seen in the output as there is only one value in the StringJoiner.
StringJoiner stringJoiner = new StringJoiner("-");
stringJoiner.add("John");
System.out.println(stringJoiner.toString()); //John
System.out.println(stringJoiner.length()); //4
Adding no value
When nothing is added to the StringJoiner, the result of calling toString will be an empty string.
StringJoiner stringJoiner = new StringJoiner("-");
System.out.println(stringJoiner.toString()); //""
StringJoiner#setEmptyValue method
We can configure a default string to be used when the StringJoiner is ‘empty’. Thus, when no values are added to the StringJoiner, it will return this special string rather than returning an empty string.
StringJoiner stringJoiner = new StringJoiner("-");
stringJoiner.setEmptyValue("NULL");
System.out.println(stringJoiner.toString()); //NULL
In the above code, we configured a string NULL as the empty value. Hence, the StringJoiner’s string representation will be this string when it is empty i.e., when no values are added to it.
Adding empty string and null to a StringJoiner
Adding an empty string to a StringJoiner will still be counted as something added to it. Hence, when calling the toString method, it will not return the string passed to the setEmptyValue method.
StringJoiner stringJoiner = new StringJoiner("-");
stringJoiner.setEmptyValue("NULL");
stringJoiner.add("");
System.out.println(stringJoiner.toString()); //""
If we add a null, it will return the string null back when calling toString.
StringJoiner stringJoiner = new StringJoiner("-");
stringJoiner.add(null);
System.out.println(stringJoiner.toString()); //"null"
System.out.println(stringJoiner.toString().length()); //4
StringJoiner with delimiter, prefix, and suffix
Now let us see the StringJoiner methods when using a prefix and suffix as well.
Configuring StringJoiner
StringJoiner stringJoiner = new StringJoiner("-", "{", "}")
We build a StringJoiner with
- - as the delimiter
- { as the prefix
- } as the suffix
Though the example shows them as single characters, they can be any CharSequence.
StringJoiner#add
StringJoiner stringJoiner = new StringJoiner("-", "{", "}")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner.toString()); //{John-Michael-Kent}
System.out.println(stringJoiner.length()); //19
It joined the passed names using the delimiter hyphen. This is exactly what we have seen before. But when we obtained the String representation of the StringJoiner, it added the prefix ({) string to the beginning of the string and suffix (}) to the end.
The length as usual will return the length of the StringJoiner’s string representation.
Adding one element
Since there is only one value added, the delimiter will not be used. But the final string will have the prefix and suffix pre-pended and appended to it, respectively.
StringJoiner stringJoiner = new StringJoiner("-", "{", "}");
stringJoiner.add("John");
System.out.println(stringJoiner.toString()); //{John}
System.out.println(stringJoiner.length()); //6
Empty StringJoiner
If the StringJoiner is empty when calling the toString i.e., no values are added, then the result will be a concatenation of prefix + suffix alone.
StringJoiner stringJoiner = new StringJoiner("-", "{", "}");
System.out.println(stringJoiner.toString()); //{}
StringJoiner setEmptyValue
The behaviour of setEmptyValue is same as seen before. It will return this string when the StringJoiner is empty. Note that the prefix and suffix are not added to this. The passed empty value string representation is returned as it is.
StringJoiner stringJoiner = new StringJoiner("-", "{", "}");
stringJoiner.setEmptyValue("NULL");
System.out.println(stringJoiner.toString()); //NULL
Adding empty string and null to a StringJoiner
As we saw before, adding empty string will still count as some value added. Hence, the StringJoiner is not considered to be empty. Hence, the string configured as to be used for empty StringJoiner is not returned.
Note that the resultant string has prefix and suffix added.
StringJoiner stringJoiner = new StringJoiner("-", "{", "}");
stringJoiner.setEmptyValue("NULL");
stringJoiner.add("");
System.out.println(stringJoiner.toString()); //"{}"
When we add a null, the result will be prefix + null as string + suffix.
StringJoiner stringJoiner = new StringJoiner("-", "{", "}");
stringJoiner.add(null);
System.out.println(stringJoiner.toString()); //{null}
StringJoiner merge for StringJoiner with delimiter, prefix and suffix
We will build two StringJoiner instances and merge the second with the first. As stated before, this will merge the string representation of the second StringJoiner (without the prefix, suffix) as the next element in the first.
StringJoiner stringJoiner1 = new StringJoiner("-", "{", "}")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString()); //{John-Michael-Kent}
StringJoiner stringJoiner2 = new StringJoiner("-", "{", "}")
.add("Adam")
.add("Steve");
System.out.println(stringJoiner2.toString()); //{Adam-Steve}
//Merge
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //{John-Michael-Kent-Adam-Steve}
The string from the second StringJoiner (Adam-Steve) is added to the first StringJoiner. The prefix and suffix will not be added again from the second Joiner.
We can continue to add more data to the first or the second StringJoiner. Let us add a value to the first StringJoiner. This will not change the second in any way.
//adding to stringJoiner1 doesn't affect stringJoiner2
stringJoiner1.add("Zac");
//adding to stringJoiner2 doesn't affect stringJoiner1
stringJoiner2.add("Simon");
System.out.println(stringJoiner1.toString()); //{John-Michael-Kent-Adam-Steve-Zac}
System.out.println(stringJoiner2.toString()); //{Adam-Steve-Simon}
Merge with a StringJoiner with a different delimiter
Let us change the delimiter of the second StringJoiner.
StringJoiner stringJoiner1 = new StringJoiner("-", "{", "}")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString()); //{John-Michael-Kent}
StringJoiner stringJoiner2 = new StringJoiner(":", "{", "}")
.add("Adam")
.add("Steve");
System.out.println(stringJoiner2.toString()); //{Adam:Steve}
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //{John-Michael-Kent-Adam:Steve}
The merge will just take the string representation of the second StringJoiner without prefix and suffix and add it as the next value of the first StringJoiner.
We can add more values to the first as shown below. It is just that the StringJoiner now has strings with multiple delimiters.
stringJoiner1.add("Zac");
System.out.println(stringJoiner1.toString()); //{John-Michael-Kent-Adam:Steve-Zac}
Merging single element StringJoiners with same delimiters
Let us merge two StringJoiner objects which has just one element in each of them.
StringJoiner stringJoiner1 = new StringJoiner("-", "{", "}");
stringJoiner1.add("John");
System.out.println(stringJoiner1.toString()); //{John}
StringJoiner stringJoiner2 = new StringJoiner("-", "{", "}");
stringJoiner2.add("Adam");
System.out.println(stringJoiner2.toString()); //{Adam}
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //{John-Adam}
Merging single element StringJoiners with different delimiters
We will now merge two StringJoiners configured with different delimiters, which has just one element in each of them.
StringJoiner stringJoiner1 = new StringJoiner("-", "{", "}");
stringJoiner1.add("John");
System.out.println(stringJoiner1.toString()); //{John}
StringJoiner stringJoiner2 = new StringJoiner(":", "{", "}");
stringJoiner2.add("Adam");
System.out.println(stringJoiner2.toString()); //{Adam}
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //{John-Adam}
After merging, the final output will use the current string joiner’s delimiter only. The other StringJoiner’s delimiter is used only for building the string.
Merging single element StringJoiners with different prefix, suffix
As you already know, the prefix and suffix of the StringJoiner that we merge with doesn’t matter. It will use the current StringJoiner’s prefix, suffix in the output string.
StringJoiner stringJoiner1 = new StringJoiner("-", "{", "}")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString()); //{John-Michael-Kent}
StringJoiner stringJoiner2 = new StringJoiner("-", "[", "]")
.add("Adam")
.add("Steve");
System.out.println(stringJoiner2.toString()); //[Adam-Steve]
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //{John-Michael-Kent-Adam-Steve}
Merge with an empty StringJoiner
When the other StringJoiner is empty, the merge has no effect.
StringJoiner stringJoiner1 = new StringJoiner("-", "{", "}")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString()); //{John-Michael-Kent}
StringJoiner stringJoiner2 = new StringJoiner("-", "[", "]");
System.out.println(stringJoiner2.toString()); //[]
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //{John-Michael-Kent}
Merge with an empty StringJoiner with emptyValue set
It is an interesting case when the other StringJoiner has set an empty value string using setEmptyValue method. This does not matter and not used when merging. It is still like the case when the other StringJoiner is empty.
Remember that a StringJoiner is empty when neither add nor merge (with a non-empty StringJoiner) was called. Calling setEmptyValue does not make a StringJoiner non-empty. It is just a placeholder string to be used for the String representation of an empty StringJoiner.
StringJoiner stringJoiner1 = new StringJoiner("-", "{", "}")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString());//{John-Michael-Kent}
StringJoiner stringJoiner2 = new StringJoiner("-", "[", "]");
stringJoiner2.setEmptyValue("NO_VALUE");
System.out.println(stringJoiner2.toString()); //NO_VALUE
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //{John-Michael-Kent}
StringJoiner merge for StringJoiner with just delimiter
For the sake of completeness, I will provide code examples for StringJoiner merge when the StringJoiners just use a delimiter. The code is self-explanatory if you have read the above section.
StringJoiner stringJoiner1 = new StringJoiner("-")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString()); //John-Michael-Kent
StringJoiner stringJoiner2 = new StringJoiner("-")
.add("Adam")
.add("Steve");
System.out.println(stringJoiner2.toString()); //Adam-Steve
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //John-Michael-Kent-Adam-Steve
Merge with a StringJoiner with a different delimiter
StringJoiner stringJoiner1 = new StringJoiner("-")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString()); //John-Michael-Kent
StringJoiner stringJoiner2 = new StringJoiner(":")
.add("Adam")
.add("Steve");
System.out.println(stringJoiner2.toString()); //Adam:Steve
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //John-Michael-Kent-Adam:Steve
Merging single element StringJoiners
Irrespective of what delimiter the other StringJoiner is using, the result is the same as they have just one value in them.
//Merge with a StringJoiner using same delimiter
StringJoiner stringJoiner1 = new StringJoiner("-");
stringJoiner1.add("John");
System.out.println(stringJoiner1.toString()); //John
StringJoiner stringJoiner2 = new StringJoiner("-");
stringJoiner2.add("Adam");
System.out.println(stringJoiner2.toString()); //Adam
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //John-Adam
//Merge with a StringJoiner using different delimiter
StringJoiner stringJoiner1 = new StringJoiner("-");
stringJoiner1.add("John");
System.out.println(stringJoiner1.toString()); //John
StringJoiner stringJoiner2 = new StringJoiner(":");
stringJoiner2.add("Adam");
System.out.println(stringJoiner2.toString()); //Adam
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //John-Adam
Merge with an empty StringJoiner
Merging with an empty StringJoiner does not change the value of the StringJoiner. This is true even if the other StringJoiner has set the empty string value using the setEmptyValue method.
StringJoiner stringJoiner1 = new StringJoiner("-")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString()); //John-Michael-Kent
StringJoiner stringJoiner2 = new StringJoiner("-");
System.out.println(stringJoiner2.toString()); // ""
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //John-Michael-Kent
StringJoiner stringJoiner1 = new StringJoiner("-")
.add("John")
.add("Michael")
.add("Kent");
System.out.println(stringJoiner1.toString()); //John-Michael-Kent
StringJoiner stringJoiner2 = new StringJoiner("-");
stringJoiner2.setEmptyValue("NO_VALUE");
System.out.println(stringJoiner2.toString()); //NO_VALUE
stringJoiner1.merge(stringJoiner2);
System.out.println(stringJoiner1); //John-Michael-Kent
Conclusion
In this post, we learnt the Java 8 StringJoiner class and the methods in it with examples. We looked at two ways to construct a StringJoiner viz., with delimiter only, and with delimiter, prefix and a suffix. We learnt the StringJoiner methods add, merge, toString, length and setEmptyValue with examples.
Have a question? Add a comment below and I’ll be happy to answer it. Also, I recommended reading through other Java 8 posts.