1
\$\begingroup\$

I have this little convenience method that takes an String array and returns an String where the values are separated by a provided separator (comma, pipe, etc).

For instance, if given an array with values "abc", "def" and "ghi", and a for separator we passed " | ", the end result would be "abc | def | ghi".

This is the method:

public String getArrayAsString(String[] stringArray, String separator) {
    StringBuilder finalString = new StringBuilder();
    boolean needsSeparator = false;
    for (String s : stringArray) {
        if (needsSeparator) {
            finalString.append(separator);
        }
        finalString.append(s);
        needsSeparator = true;
    }
    return finalString.toString();
}

Notice that the separator must, as its name implies, separate values, and not be appended or prepended artificially to the final String. So, for instance, the following would be incorrect return values: "abc | def | ghi | " or " | abc | def | ghi".

I specifically don't like the needsSeparator flag variable, but without it, the unwanted leading or trailing separators would be added, and then I would need to remove them from the finalString before returning it, which I also don't find to be very elegant.

Is there a more concise (perhaps more elegant) way to achieve this?

\$\endgroup\$

4 Answers 4

4
\$\begingroup\$

Before I review your code I want to point out that Java has a String.join() method which does exactly that. Now to your code:

You use StringBuilder, good. You take care of not appending a seperator after the last and not prepending before the first element, also good. You don't handle null values though, it's your decision if you want to handle them separately or just let Java just throw a NPE. For the separator however, a null appends literally null to the String, I'd rather default to "" if separator is null. A way to get rid of the flag:

public String getArrayAsString(String[] stringArray, String separator) {
    if(stringArray == null || stringArray.length == 0) return "";

With this we already ensured that our stringArray has at least one entry. What we can do now is initialize the StringBuilder with the first String:

    StringBuilder finalString = new StringBuilder(stringArray[0]);

Since all strings after the first one need to prepend the separator, we don't need the flag anymore. Unfortunately, we can't use a foreach loop, since we have to start at index 1 as the element at index 0 is already in the StringBuilder:

    for(int i = 1; i < stringArray.length; ++i)
        finalString.append(separator).append(stringArray[i]);

And then just return what we got:

    return finalString.toString();

Whole function:

public String getArrayAsString(String[] stringArray, String separator) {
    if(stringArray == null || stringArray.length == 0) return "";

    StringBuilder finalString = new StringBuilder(stringArray[0]);

    for(int i = 1; i < stringArray.length; ++i)
        finalString.append(separator).append(stringArray[i]);

    return finalString.toString();
}

Edit:

In String.join() the parameters are swapped, so the separator comes first, the array second:

    String[] arr = new String[]{"Hello", "World"};
    System.out.println(String.join(" | ", arr));
    System.out.println(getArrayAsString(arr, " | ")); //Your function

Output:

Hello | World
Hello | World

Working code at ideone.com

\$\endgroup\$
1
  • \$\begingroup\$ Didn't know about String.join(). I just saw that it works taking an array of Strings as an argument. Beautiful! \$\endgroup\$ Commented Sep 7, 2016 at 23:24
2
\$\begingroup\$

I would probably drop an enchanced loop, and stick to indices:

    finalString.append(stringArray[0]);
    for (int i = 1; i < stringArray.size(); ++i) {
        finalString.append(separator);
        finalString.append(s);
    }

You may try to keep the enchanced loop by wrapping the array into a List, get a List.sublist(1)and iterate over it. However I am not sure it is more concise/elegant.

\$\endgroup\$
1
\$\begingroup\$

Much is already said, i.e. about join.

My point would be the possibility of adding something to the API usage with varargs:

public static String arrayAsString(String separator, String... strings) {

Optimizing StringBuilder with an adequate initial size, so hopefully no reallocations need to be done.

    StringBuilder finalString = new StringBuilder(stringArray.length * 16);
\$\endgroup\$
0
\$\begingroup\$

Minor thing: I find finalString isn't a good name for that. Yes, that builder is used to create that "final" string, but it isn't itself the final string.

So, maybe, builder something alike would be more "telling".

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.