136

I am looking for a method to combine an array of strings into a delimited String. An opposite to split().

Wanted to ask the forum before I try writing my own (since the JDK has everything)

philipxy
  • 14,867
  • 6
  • 39
  • 83
javaphild
  • 1,511
  • 3
  • 12
  • 6
  • 1
    Just iterate over the array and concatenate the elements into a StringBuilder. – Steve Kuo Apr 27 '09 at 16:56
  • 5
    Duplicate of http://stackoverflow.com/questions/63150/whats-the-best-way-to-build-a-string-of-delimited-items-in-java, http://stackoverflow.com/questions/448320/how-do-i-append-a-newline-character-for-all-lines-except-the-last-one, http://stackoverflow.com/questions/205555/the-most-sophisticated-way-for-creating-comma-separated-strings-from-a-collection, http://stackoverflow.com/questions/58431/algorithm-for-joining-e-g-an-array-of-strings, and several others. – Michael Myers Apr 27 '09 at 17:25
  • 3
    Thanks. I did write such a method, but after re-inventing the wheel so many times in the past, and then finding out that the jdk already had it...well, figured it was wroth the post.. Phil – javaphild Apr 27 '09 at 19:39
  • You may only estimate, if the input was split with an regular expression like this: `s = "foo:bar,baz".split ("[:,]")` – user unknown May 25 '11 at 14:50
  • Please see Arrays.toString(Object[]) as per @DenTheMan's answer below – earcam Feb 06 '13 at 11:40

16 Answers16

97

There's no method in the JDK for this that I'm aware of. Apache Commons Lang has various overloaded join() methods in the StringUtils class that do what you want.

Elazar
  • 20,415
  • 4
  • 46
  • 67
John Topley
  • 113,588
  • 46
  • 195
  • 237
56

There has been an open feature request since at least 2009. The long and short of it is that it will part of the functionality of JDK 8's java.util.StringJoiner class. http://download.java.net/lambda/b81/docs/api/java/util/StringJoiner.html

Here is the Oracle issue if you are interested. http://bugs.sun.com/view_bug.do?bug_id=5015163

Here is an example of the new JDK 8 StringJoiner on an array of String

String[] a = new String[]{"first","second","third"};
StringJoiner sj = new StringJoiner(",");
for(String s:a) sj.add(s);
System.out.println(sj); //first,second,third

A utility method in String makes this even simpler:

String s = String.join(",", stringArray);
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
Nathaniel Johnson
  • 4,731
  • 1
  • 42
  • 69
25

You can sneak this functionality out of the Arrays utility package.

import java.util.Arrays;
...
    String delim = ":",
            csv_record = "Field0:Field1:Field2",
            fields[] = csv_record.split(delim);

    String rebuilt_record = Arrays.toString(fields)
            .replace(", ", delim)
            .replaceAll("[\\[\\]]", "");
Brad Turek
  • 2,472
  • 3
  • 30
  • 56
David Howard
  • 267
  • 3
  • 3
  • 12
    A bit late, but that sounds like a generally bad idea, unless you know with absolute certainty that there can never be a ', ' in your strings. And then it's probably far from efficient. – John Chadwick Jun 08 '13 at 22:03
16

I got the following example here

/*
7) Join Strings using separator >>>AB$#$CD$#$EF

 */

import org.apache.commons.lang.StringUtils;

public class StringUtilsTrial {
  public static void main(String[] args) {

    // Join all Strings in the Array into a Single String, separated by $#$
    System.out.println("7) Join Strings using separator >>>"
        + StringUtils.join(new String[] { "AB", "CD", "EF" }, "$#$"));
  }
}
Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Azder
  • 4,698
  • 7
  • 37
  • 57
12

Google also provides a joiner class in their Google Collections library:

Joiner API

Google Collections

Blair Zajac
  • 4,555
  • 3
  • 25
  • 36
10

There are several examples on DZone Snippets if you want to roll your own that works with a Collection. For example:

public static String join(AbstractCollection<String> s, String delimiter) {
    if (s == null || s.isEmpty()) return "";
    Iterator<String> iter = s.iterator();
    StringBuilder builder = new StringBuilder(iter.next());
    while( iter.hasNext() )
    {
        builder.append(delimiter).append(iter.next());
    }
    return builder.toString();
}
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
  • I would be inclined to leave out the empty check, because the behavior will be the same and why complicate the code with special cases? On the other hand, a null check might be in order. – Carl Manaster Apr 27 '09 at 16:43
  • @Carl: I completely agree with you on the null check and added that. Checking for an empty Collection allows the function to skip needlessly creating an Iterator and a StringBuffer, so I left it in. – Bill the Lizard Apr 27 '09 at 16:50
  • 1
    You should use StringBuilder instead of StringBuffer as StringBuffer has the added overhead of being synchronized. You don't need synchronization for method variables (since only one thread will be using it). – Steve Kuo Apr 27 '09 at 16:55
  • 1
    Your join method should accept Collection, not AbstractCollection. Better yet, it could accept Iterable, which allows it to be more generic. – Steve Kuo Apr 27 '09 at 17:26
  • @Steve: Either of those would be acceptable. You can make it as abstract or specific as you need. There's a later example on the page I linked to that accepts Iterable. – Bill the Lizard Apr 27 '09 at 18:09
  • You can also use the " extends Object>" generic type along with "iter.next().toString()" to be able to join string representation of Integers and other types. – tomash Jun 06 '14 at 08:24
7

If you have an int[], Arrays.toString() is the easiest way.

DenTheMan
  • 1,277
  • 2
  • 13
  • 21
  • 1
    Actually this works for String[] too, using Arrays.toString(Object[]) This has been available since Java 1.5 which was released in 2004 _eons_ before the question was posted. This is the **correct** answer, if you don't mind the prefix "[" and suffix "]". – earcam Feb 06 '13 at 11:40
4

Based on all the previous answers:

public static String join(Iterable<? extends Object> elements, CharSequence separator) 
{
    StringBuilder builder = new StringBuilder();

    if (elements != null)
    {
        Iterator<? extends Object> iter = elements.iterator();
        if(iter.hasNext())
        {
            builder.append( String.valueOf( iter.next() ) );
            while(iter.hasNext())
            {
                builder
                    .append( separator )
                    .append( String.valueOf( iter.next() ) );
            }
        }
    }

    return builder.toString();
}
Sarabjot
  • 489
  • 1
  • 4
  • 13
  • I think this is the better way to do it, simple and efficient. Also to be mentioned is that apache use a simple for with a if inside and openjdk8 do something like yours but in separated methods. – PhoneixS Feb 19 '15 at 13:07
  • You'll be pleased to know that Java 8 lets you do this with the built-in `String.join()` method now. – Brad Turek Jan 06 '21 at 20:22
3

For Android: in android.text.TextUtils there are methods:

public static String join (CharSequence delimiter, Iterable tokens)
public static String join (CharSequence delimiter, Object[] tokens)

Returns a string containing the tokens joined by delimiters.

tokens -- an array objects to be joined. Strings will be formed from the objects by calling object.toString().

18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
3

Since JDK8 I love Streams and Lambdas a lot, so I would suggest:

public static String join( String delimiter, String[] array )
{
    return Arrays.asList( array ).stream().collect( Collectors.joining( delimiter ) );
}
Radouxca
  • 144
  • 1
  • 7
2

For the sake of completeness, I'd like to add that you cannot reverse String#split in general, as it accepts a regular expression.

"hello__world".split("_+"); Yields ["hello", "world"].
"hello_world".split("_+"); Yields ["hello", "world"].

These yield identical results from a different starting point. splitting is not a one-to-one operation, and is thus non-reversible.

This all being said, if you assume your parameter to be a fixed string, not regex, then you can certainly do this using one of the many posted answers.

Cruncher
  • 7,641
  • 1
  • 31
  • 65
1

This one is not bad too :

public static String join(String delimitor,String ... subkeys) {
    String result = null;
    if(null!=subkeys && subkeys.length>0) {
        StringBuffer joinBuffer = new StringBuffer(subkeys[0]);
        for(int idx=1;idx<subkeys.length;idx++) {
            joinBuffer.append(delimitor).append(subkeys[idx]);
        }
        result = joinBuffer.toString();
    }
    return result;
}
1

I wrote this one:

public static String join(Collection<String> col, String delim) {
    StringBuilder sb = new StringBuilder();
    Iterator<String> iter = col.iterator();
    if (iter.hasNext())
        sb.append(iter.next());
    while (iter.hasNext()) {
        sb.append(delim);
        sb.append(iter.next());
    }
    return sb.toString();
}

Collection isn't supported by JSP, so for TLD I wrote:

public static String join(List<?> list, String delim) {
    int len = list.size();
    if (len == 0)
        return "";
    StringBuilder sb = new StringBuilder(list.get(0).toString());
    for (int i = 1; i < len; i++) {
        sb.append(delim);
        sb.append(list.get(i).toString());
    }
    return sb.toString();
}

and put to .tld file:

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
    <function>
        <name>join</name>
        <function-class>com.core.util.ReportUtil</function-class>
        <function-signature>java.lang.String join(java.util.List, java.lang.String)</function-signature>
    </function>
</taglib>

and use it in JSP files as:

<%@taglib prefix="funnyFmt" uri="tag:com.core.util,2013:funnyFmt"%>
${funnyFmt:join(books, ", ")}
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
1

If you use jdk8 see @Nathaniel Johnson's answer as that is better.

I think that many of the answer here are complex or not easily read. With branch prediction so efficient why you simply not use a if statement?

public static String join(List<String> fooList){

    if (fooList.isEmpty()) return "";

    StringBuilder sb = null;

    for (String element : fooList) {

        if (sb == null) {
            sb = new StringBuilder();
        } else {
            sb.append(", ");
        }

        sb.append(element);
    }
    return sb.toString();
}

Something that should be mentioned is that Apache uses a simple for loop with an if statement inside it like this (it uses an array as its index to know the first element), and openjdk 8 does the same but in separated methods calls instead of a simple loop.

Community
  • 1
  • 1
PhoneixS
  • 10,574
  • 6
  • 57
  • 73
1

Below code gives a basic idea. This is not best solution though.

public static String splitJoin(String sourceStr, String delim,boolean trim,boolean ignoreEmpty){
    return join(Arrays.asList(sourceStr.split(delim)), delim, ignoreEmpty);
}


public static String join(List<?> list, String delim, boolean ignoreEmpty) {
    int len = list.size();
    if (len == 0)
        return "";
    StringBuilder sb = new StringBuilder(list.get(0).toString());
    for (int i = 1; i < len; i++) {
        if (ignoreEmpty && !StringUtils.isBlank(list.get(i).toString())) {
            sb.append(delim);
            sb.append(list.get(i).toString().trim());
        }
    }
    return sb.toString();
}
0

I like this better:

public String join(Collection<String> strCollection, String delimiter) {
    String joined = "";
    int noOfItems = 0;
    for (String item : strCollection) {
        joined += item;
        if (++noOfItems < strCollection.size())
            joined += delimiter;
    }
    return joined;
}

It is the neatest solution I have found so far. (Don't worry about the use of raw String objects instead of StringBuilder. Modern Java compilers use StringBuilder anyway, but this code is more readable).

Luis
  • 9
  • 1