270

I want to join a String[] with a glue string. Is there a function for this?

philipxy
  • 14,867
  • 6
  • 39
  • 83
Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
  • 7
    Java 8 has this functionality included out of the box. I recommend the reader to scroll through to the answer by @Marek Gregor (and upvote it..) – stav Jul 08 '14 at 15:53
  • Possible duplicate of [A quick and easy way to join array elements with a separator (the opposite of split) in Java](http://stackoverflow.com/questions/1978933/a-quick-and-easy-way-to-join-array-elements-with-a-separator-the-opposite-of-sp) – Anderson Green Oct 04 '15 at 01:03

24 Answers24

318

Starting from Java8 it is possible to use String.join().

String.join(", ", new String[]{"Hello", "World", "!"})

Generates:

Hello, World, !

Otherwise, Apache Commons Lang has a StringUtils class which has a join function which will join arrays together to make a String.

For example:

StringUtils.join(new String[] {"Hello", "World", "!"}, ", ")

Generates the following String:

Hello, World, !
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
coobird
  • 159,216
  • 35
  • 211
  • 226
  • 7
    For the benefit of people searching for this answer, it should probably be noted that this is also the equivalent of a Perl join. – k-den Feb 14 '13 at 23:17
  • 3
    it says it's undefined for me – Ninjaxor Apr 08 '13 at 01:31
  • @Ninjaxor 1. commons-lang*jar must be in classpath 2. import org.apache.commons.lang3.StringUtils; – peterh Aug 21 '14 at 08:54
  • 9
    I would recommend you edit this answer to append a reference to the new [`String.join()`](http://docs.oracle.com/javase/8/docs/api/java/lang/String.html#join-java.lang.CharSequence-java.lang.CharSequence...-) method introduced in Java 8. This way, the huge numbers of people reading this accepted answer will benefit from that knowledge. Currently, the highest voted answer mentioning this fact is rather lost down below... – Duncan Jones Mar 12 '15 at 15:37
  • For gradle: `compile 'org.apache.commons:commons-lang3:3.3.2'` – Elliot Chance Mar 19 '15 at 23:35
  • 1
    It's worth mentioning that `String.join()` would work only for `List` or `CharSequence[]` elements. – Enigo Nov 18 '16 at 07:55
  • Look also @Marek Gregor answer below as it mentions the Java stream+collect way: `Arrays.stream(a).collect(Collectors.joining(", "));` – luv2learn Dec 19 '18 at 00:40
73

If you were looking for what to use in android, it is:

String android.text.TextUtils.join(CharSequence delimiter, Object[] tokens)

for example:

String joined = TextUtils.join(";", MyStringArray);
Noah
  • 15,080
  • 13
  • 104
  • 148
  • 2
    This is clearly the best answer for all Android versions, as Java 8 is only coming out on Android in a bit. This solution uses the built in Android libs, rather than these silly "include a huge lib to perform one action" solutions. – LukeStoneHm Aug 26 '15 at 14:57
  • It's September 2017, Java 8 for Android is still far away. Thanks for this answer! – techfly Sep 16 '17 at 15:15
58

In Java 8 you can use

1) Stream API :

String[] a = new String[] {"a", "b", "c"};
String result = Arrays.stream(a).collect(Collectors.joining(", "));

2) new String.join method: https://stackoverflow.com/a/21756398/466677

3) java.util.StringJoiner class: http://docs.oracle.com/javase/8/docs/api/java/util/StringJoiner.html

Community
  • 1
  • 1
Marek Gregor
  • 3,691
  • 2
  • 26
  • 28
53

You could easily write such a function in about ten lines of code:

String combine(String[] s, String glue)
{
  int k = s.length;
  if ( k == 0 )
  {
    return null;
  }
  StringBuilder out = new StringBuilder();
  out.append( s[0] );
  for ( int x=1; x < k; ++x )
  {
    out.append(glue).append(s[x]);
  }
  return out.toString();
}
Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
Jay
  • 26,876
  • 10
  • 61
  • 112
  • 35
    Good practice according to you...there is no universal standard for such things. – phoebus Oct 04 '09 at 05:47
  • 2
    Yes, always use the curly braces. It's what makes Java so nice and cosy! Even though SUN does not always add them in their own code samples. – Adriaan Koster Oct 04 '09 at 12:16
  • 24
    But if I included braces, that would have added two more lines of code, and I couldn't have claimed to have done it in 11 lines! – Jay Oct 04 '09 at 21:22
  • 8
    the problem is when you after a while, or someone else, in a hurry, add another line to that if/for without adding braces; or delete return null after if(k==0), whih in some cases would compiles but will be incorrect. Then it's better to sacrifice one extra line for that closing brace (the opening can stay in the same if/for line). – milan Dec 14 '10 at 17:07
  • 7
    We're off on a tangent here, but personally i often omit the braces when there's only one line, especially if it's a big if/elseif/elseif structure, for compactness. But when theres an if/else and either branch requires braces, I put it on both for symmetry. I'm not going to worry about someone adding a line and not realizing that he needs to add the braces. If a programmer does not know that he needs braces when there's more than one line in the block, I have no confidence that he has any clue what to put inside the block. – Jay Dec 14 '10 at 17:58
  • 16
    I think it's awesome that while most languages pack such functionality into their core, the Java community encourages everyone to reinvent the wheel. – John Strickler Apr 25 '11 at 20:09
  • 1
    @Strickler: Personally, I prefer to have a small set of simple but flexible tools, so anything I need I can build easily, rather than a huge set of complex tools, so anything I need I have figure out exactly what each tool does and how to beat it into doing what I want. – Jay Apr 26 '11 at 16:02
  • 34
    11 lines? Bah! I can do it in 1! Simply remove all the newline characters in the source file. – Thomas Eding Aug 03 '11 at 20:24
  • 4
    @milan That's why I usually prefer to think before writing the code and not to push random statements all around. It's just a wrong thing to add useless braces and what not to help some idiots to imitate work(doing destructive things mostly). – stroncium Sep 21 '11 at 12:02
  • 8
    Spending time on implementing it yourself, placing it in some random package, and naming it 'combine' instead of 'join' already seem like three bad practices to me. – Martin Konicek May 29 '12 at 13:14
  • For a simple function like that, I'd rather spend 2 hours writing and debugging it myself than spend 4 hours searching the web to find code that someone else has written. "Free code" is not really free: you still have to spend time searching for it, verifying that it meets your needs, and figuring out how to use it. And there's no guarantee that it's bug-free. Factories routinely debate "make or buy": is it more cost effective to make something ourselves or to buy it from others? Real manufacturers reinvent the wheel all the time. There's more than one company in the world that makes wheels. – Jay May 29 '12 at 21:56
  • 1
    reinventing the wheel might be error prone. also you don't want a trailing , – Cosmin Cosmin Jul 04 '12 at 13:07
  • Assuming the comma is in "glue", then the above code would not put a trailing comma. Note the glue is appended before the next token. – Jay Jul 05 '12 at 07:14
  • 4
    Java is compiled into bytecode, so we don't need to minify it - make the code as readable and maintainable as possible. – Aram Kocharyan Sep 30 '12 at 10:32
  • 4
    "To summarize, don’t reinvent the wheel. If you need to do something that seems like it should be reasonably common, there may already be a class in the libraries that does what you want. If there is, use it; if you don’t know, check. Generally speaking, library code is likely to be better than code that you’d write yourself and is likely to improve over time. This is no reflection on your abilities as a programmer. Economies of scale dictate that library code receives far more attention than most developers could afford to devote to the same functionality." Bloch, Effective Java (2nd Edition) – Colin K Mar 28 '13 at 20:31
  • 3
    Yes, I'm not going to re-write a function that's already in the standard String class. But I'm also not going to spend unlimited amounts of time searching the web for a solution to a problem that I could easily code myself in an hour or two. Is that "re-inventing the wheel"? I suppose so. Just like physical manufacturers re-invent the wheel every day. Do you think that there's only one factory in the world that makes wheels, and everyone else buys from them? No? Why not? Because sometimes you want a wheel with different specifications from somebody else's, ... – Jay Apr 02 '13 at 16:59
  • 2
    ... like the wheel for a child's toy truck is probably not suitable for a full-size truck. And because sometimes it's cheaper to make your own wheels rather than to buy them from someone else. Of course there are economies of scale in having one big factory rather than 100 little factories. But there are many, many factors that go into total cost, and scale is only one of them. – Jay Apr 02 '13 at 17:01
  • @AramKocharyan But humans read it. [And, more importantly, humans write it](http://programmers.stackexchange.com/questions/185660/is-the-average-number-of-bugs-per-loc-the-same-for-different-programming-languag). Besides which, the fewer lines of code, the less you have to skip around to look for things. Minify your code, dammit... – Parthian Shot Aug 12 '14 at 21:04
  • @milan ...Or you could save a line by putting the one statement to be executed on the same line as the if-block, thus both saving space in a ratio of 4:1 and obviating the risk of accidentally divorcing the two constructs. – Parthian Shot Aug 12 '14 at 21:07
  • @AramKocharyan The purpose of minifying code is not because this will make the executable smaller or make it run faster. The purpose is to make it easier to read. I suppose some will say that always using braces even when they're not necessary makes the code easier to read because it is more consistent, while others say that it makes it harder to read because it is now unnecessarily longer. Personally I'm in group B, but I can comprehend group A. – Jay Aug 20 '14 at 14:54
27

A little mod instead of using substring():

//join(String array,delimiter)
public static String join(String r[],String d)
{
        if (r.length == 0) return "";
        StringBuilder sb = new StringBuilder();
        int i;
        for(i=0;i<r.length-1;i++){
            sb.append(r[i]);
            sb.append(d);
        }
        sb.append(r[i]);
        return sb.toString();
}
everlasto
  • 4,890
  • 4
  • 24
  • 31
18

As with many questions lately, Java 8 to the rescue:


Java 8 added a new static method to java.lang.String which does exactly what you want:

public static String join(CharSequence delimeter, CharSequence... elements);

Using it:

String s = String.join(", ", new String[] {"Hello", "World", "!"});

Results in:

"Hello, World, !"
icza
  • 389,944
  • 63
  • 907
  • 827
14

Google guava's library also has this kind of capability. You can see the String[] example also from the API.

As already described in the api, beware of the immutability of the builder methods.

It can accept an array of objects so it'll work in your case. In my previous experience, i tried joining a Stack which is an iterable and it works fine.

Sample from me :

Deque<String> nameStack = new ArrayDeque<>();
nameStack.push("a coder");
nameStack.push("i am");
System.out.println("|" + Joiner.on(' ').skipNulls().join(nameStack) + "|");

prints out : |i am a coder|

Bertie
  • 17,277
  • 45
  • 129
  • 182
9

If you are using the Spring Framework then you have the StringUtils class:

import static org.springframework.util.StringUtils.arrayToDelimitedString;

arrayToDelimitedString(new String[] {"A", "B", "C"}, "\n");
devstopfix
  • 6,698
  • 4
  • 34
  • 32
9

Given:

String[] a = new String[] { "Hello", "World", "!" };

Then as an alternative to coobird's answer, where the glue is ", ":

Arrays.asList(a).toString().replaceAll("^\\[|\\]$", "")

Or to concatenate with a different string, such as " &amp; ".

Arrays.asList(a).toString().replaceAll(", ", " &amp; ").replaceAll("^\\[|\\]$", "")

However... this one ONLY works if you know that the values in the array or list DO NOT contain the character string ", ".

Rob at TVSeries.com
  • 2,397
  • 1
  • 21
  • 17
8

Not in core, no. A search for "java array join string glue" will give you some code snippets on how to achieve this though.

e.g.

public static String join(Collection s, String delimiter) {
    StringBuffer buffer = new StringBuffer();
    Iterator iter = s.iterator();
    while (iter.hasNext()) {
        buffer.append(iter.next());
        if (iter.hasNext()) {
            buffer.append(delimiter);
        }
    }
    return buffer.toString();
}
  • 2
    Use StringBuilder (non-thread-safe) in place of StringBuffer (thread-safe) for better performance. The interface is the same. – Asaph Oct 04 '09 at 04:36
  • 2
    This seems to be from http://snippets.dzone.com/posts/show/91. The comments suggest a much improved version: public static String join( Iterable< ? extends Object > pColl, String separator ) { Iterator< ? extends Object > oIter; if ( pColl == null || ( !( oIter = pColl.iterator() ).hasNext() ) ) return ""; StringBuilder oBuilder = new StringBuilder( String.valueOf( oIter.next() ) ); while ( oIter.hasNext() ) oBuilder.append( separator ).append( oIter.next() ); return oBuilder.toString(); } – Quantum7 Mar 17 '10 at 22:03
6

If you've landed here looking for a quick array-to-string conversion, try Arrays.toString().

Creates a String representation of the Object[] passed. The result is surrounded by brackets ("[]"), each element is converted to a String via the String.valueOf(Object) and separated by ", ". If the array is null, then "null" is returned.

quietmint
  • 13,885
  • 6
  • 48
  • 73
5

Just for the "I've the shortest one" challenge, here are mines ;)

Iterative:

public static String join(String s, Object... a) {
    StringBuilder o = new StringBuilder();
    for (Iterator<Object> i = Arrays.asList(a).iterator(); i.hasNext();)
        o.append(i.next()).append(i.hasNext() ? s : "");
    return o.toString();
}

Recursive:

public static String join(String s, Object... a) {
    return a.length == 0 ? "" : a[0] + (a.length == 1 ? "" : s + join(s, Arrays.copyOfRange(a, 1, a.length)));
}
sp00m
  • 47,968
  • 31
  • 142
  • 252
4

Nothing built-in that I know of.

Apache Commons Lang has a class called StringUtils which contains many join functions.

JonMR
  • 586
  • 3
  • 18
4

This is how I do it.

private String join(String[] input, String delimiter)
{
    StringBuilder sb = new StringBuilder();
    for(String value : input)
    {
        sb.append(value);
        sb.append(delimiter);
    }
    int length = sb.length();
    if(length > 0)
    {
        // Remove the extra delimiter
        sb.setLength(length - delimiter.length());
    }
    return sb.toString();
}
Richard Corfield
  • 717
  • 6
  • 19
2

A similar alternative

/**
 * @param delimiter 
 * @param inStr
 * @return String
 */
public static String join(String delimiter, String... inStr)
{
    StringBuilder sb = new StringBuilder();
    if (inStr.length > 0)
    {
        sb.append(inStr[0]);
        for (int i = 1; i < inStr.length; i++)
        {
            sb.append(delimiter);                   
            sb.append(inStr[i]);
        }
    }
    return sb.toString();
}
2

My spin.

public static String join(Object[] objects, String delimiter) {
  if (objects.length == 0) {
    return "";
  }
  int capacityGuess = (objects.length * objects[0].toString().length())
      + ((objects.length - 1) * delimiter.length());
  StringBuilder ret = new StringBuilder(capacityGuess);
  ret.append(objects[0]);
  for (int i = 1; i < objects.length; i++) {
    ret.append(delimiter);
    ret.append(objects[i]);
  }
  return ret.toString();
}

public static String join(Object... objects) {
  return join(objects, "");
}
Jackson
  • 9,188
  • 6
  • 52
  • 77
1

Do you like my 3-lines way using only String class's methods?

static String join(String glue, String[] array) {
    String line = "";
    for (String s : array) line += s + glue;
    return (array.length == 0) ? line : line.substring(0, line.length() - glue.length());
}
Ryoichiro Oka
  • 1,949
  • 2
  • 13
  • 20
0

To get "str1, str2" from "str1", "str2", "" :

Stream.of("str1", "str2", "").filter(str -> !str.isEmpty()).collect(Collectors.joining(", ")); 

Also you can add extra null-check

ema
  • 891
  • 11
  • 21
0

In case you're using Functional Java library and for some reason can't use Streams from Java 8 (which might be the case when using Android + Retrolambda plugin), here is a functional solution for you:

String joinWithSeparator(List<String> items, String separator) {
    return items
            .bind(id -> list(separator, id))
            .drop(1)
            .foldLeft(
                    (result, item) -> result + item,
                    ""
            );
}

Note that it's not the most efficient approach, but it does work good for small lists.

Dmitry Zaytsev
  • 23,650
  • 14
  • 92
  • 146
0

Whatever approach you choose, be aware of null values in the array. Their string representation is "null" so if it is not your desired behavior, skip null elements.

String[] parts = {"Hello", "World", null, "!"};
Stream.of(parts)
      .filter(Objects::nonNull)
      .collect(Collectors.joining(" "));
Mr.Q
  • 4,316
  • 3
  • 43
  • 40
0

As already mentioned, class StringJoiner is also an available option since Java 8:

@NotNull
String stringArrayToCsv(@NotNull String[] data) {
    if (data.length == 0) {return "";}
    StringJoiner joiner = new StringJoiner(", ");
    Iterator<String> itr = Arrays.stream(data).iterator();
    while (itr.hasNext()) {joiner.add(itr.next());}
    return joiner.toString();
}

However, the traditional String.join() is less imports and less code:

@NotNull
String stringArrayToCsv(@NotNull String[] data) {
    if (data.length == 0) {return "";}
    return String.join(", ", data);
}
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
-1

I do it this way using a StringBuilder:

public static String join(String[] source, String delimiter) {
    if ((null == source) || (source.length < 1)) {
        return "";
    }

    StringBuilder stringbuilder = new StringBuilder();
    for (String s : source) {
        stringbuilder.append(s + delimiter);
    }
    return stringbuilder.toString();
} // join((String[], String)
spanky762
  • 171
  • 1
  • 11
  • 1
    `s + delimiter` (string concatenation with the plus operator) defeats the whole purpose of using a `StringBuilder`. – quietmint May 29 '13 at 00:19
  • Plus, this approach would mean that an array like: {"foo", "bar"} with delimiter ":" would be turned into "foo:bar:" – pioto Feb 07 '14 at 20:12
-2

There is simple shorthand technique I use most of the times..

String op = new String;
for (int i : is) 
{
    op += candidatesArr[i-1]+",";
}
op = op.substring(0, op.length()-1);
Gaurav Adurkar
  • 834
  • 8
  • 9
-3

java.util.Arrays has an 'asList' method. Together with the java.util.List/ArrayList API this gives you all you need:;

private static String[] join(String[] array1, String[] array2) {

    List<String> list = new ArrayList<String>(Arrays.asList(array1));
    list.addAll(Arrays.asList(array2));
    return list.toArray(new String[0]);
}
Adriaan Koster
  • 15,870
  • 5
  • 45
  • 60
  • 7
    The question is how to join an array of string with a delimiter, not how to join two arrays of strings together. –  Jan 21 '10 at 19:30