112

What is the clearest way to comma-delimit a list in Java?

I know several ways of doing it, but I'm wondering what the best way is (where "best" means clearest and/or shortest, not the most efficient.

I have a list and I want to loop over it, printing each value. I want to print a comma between each item, but not after the last one (nor before the first one).

List --> Item ( , Item ) *
List --> ( Item , ) * Item

Sample solution 1:

boolean isFirst = true;
for (Item i : list) {
  if (isFirst) {
    System.out.print(i);        // no comma
    isFirst = false;
  } else {
    System.out.print(", "+i);   // comma
  }
}

Sample solution 2 - create a sublist:

if (list.size()>0) {
  System.out.print(list.get(0));   // no comma
  List theRest = list.subList(1, list.size());
  for (Item i : theRest) {
    System.out.print(", "+i);   // comma
  }
}

Sample solution 3:

  Iterator<Item> i = list.iterator();
  if (i.hasNext()) {
    System.out.print(i.next());
    while (i.hasNext())
      System.out.print(", "+i.next());
  }

These treat the first item specially; one could instead treat the last one specially.

Incidentally, here is how List toString is implemented (it's inherited from AbstractCollection), in Java 1.6:

public String toString() {
    Iterator<E> i = iterator();
    if (! i.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = i.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! i.hasNext())
            return sb.append(']').toString();
        sb.append(", ");
    }
}

It exits the loop early to avoid the comma after the last item. BTW: this is the first time I recall seeing "(this Collection)"; here's code to provoke it:

List l = new LinkedList();
l.add(l);
System.out.println(l);

I welcome any solution, even if they use unexpected libraries (regexp?); and also solutions in languages other than Java (e.g. I think Python/Ruby have an intersperse function - how is that implemented?).

Clarification: by libraries, I mean the standard Java libraries. For other libraries, I consider them with other languages, and interested to know how they're implemented.

EDIT toolkit mentioned a similar question: Last iteration of enhanced for loop in java

And another: Does the last element in a loop deserve a separate treatment?

1

30 Answers 30

248

Java 8 and later

Using StringJoiner class, and forEach method :

StringJoiner joiner = new StringJoiner(",");
list.forEach(item -> joiner.add(item.toString());
return joiner.toString();

Using Stream, and Collectors:

return list.stream().
       map(Object::toString).
       collect(Collectors.joining(",")).toString();

Java 7 and earlier

See also #285523

String delim = "";
for (Item i : list) {
    sb.append(delim).append(i);
    delim = ",";
}
7
  • 1
    A very surprising way to store state! It's almost OO polymorphic. I don't like the unnecessary assignment every loop, but I bet it's more efficient than an if. Most solutions repeat a test we know won't be true - though inefficient, they're probably the clearest. Thanks for the link!
    – 13ren
    Commented Mar 21, 2009 at 12:03
  • 1
    I like this, but because it's clever and surprising, I thought it wouldn't be appropriate to use (surprising is not good!). However, I couldn't help myself. I'm still not sure about it; however, it is so short that it is easy to work out provided there's a comment to tip you off.
    – 13ren
    Commented Mar 25, 2009 at 7:29
  • 6
    @13ren: You and Uncle Bob need to have a talk about code that is "clever and surprising." Commented Aug 31, 2011 at 1:11
  • I feel like I wasted years not knowing this^^;
    – Lake
    Commented Aug 10, 2015 at 7:02
  • Why Java needs to turn such task into an ugly code?
    – Eduardo
    Commented Oct 24, 2015 at 21:22
84
org.apache.commons.lang3.StringUtils.join(list,",");
4
  • 1
    Found the source: svn.apache.org/viewvc/commons/proper/lang/trunk/src/java/org/… The join method has 9 overloadings. The iteration-based ones are like "Sample solution 3"; the index-based ones use: if (i > startIndex) { <add separator> }
    – 13ren
    Commented Mar 21, 2009 at 11:15
  • I'm really after implementations though. It's a good idea to wrap it up in a function, but in practice, my delimiter is sometimes a newline, and each line is also indented to some specified depth. Unless... join(list, "\n"+indent) ...will that always work? Sorry, just thinking aloud.
    – 13ren
    Commented Mar 21, 2009 at 13:04
  • 2
    In my opinion, this is the prettiest and shortest solution Commented Mar 17, 2011 at 9:10
  • probably, list.iterator()?
    – Vanuan
    Commented Aug 30, 2013 at 17:00
36

Java 8 provides several new ways to do this:

Example:

// Util method for strings and other char sequences
List<String> strs = Arrays.asList("1", "2", "3");
String listStr1 = String.join(",", strs);

// For any type using streams and collectors
List<Object> objs = Arrays.asList(1, 2, 3);
String listStr2 = objs.stream()
    .map(Object::toString)
    .collect(joining(",", "[", "]"));

// Using the new StringJoiner class
StringJoiner joiner = new StringJoiner(", ", "[", "]");
joiner.setEmptyValue("<empty>");
for (Integer i : objs) {
  joiner.add(i.toString());
}
String listStr3 = joiner.toString();

The approach using streams assumes import static java.util.stream.Collectors.joining;.

1
  • 1
    This is IMHO, if you are using java 8, the best answer.
    – scravy
    Commented Nov 3, 2015 at 10:40
20
Joiner.on(",").join(myList)

Joiner.

1
  • I came here looking for something that does exactly this. Thanks! +1 Commented Mar 25, 2013 at 23:07
7

If you use the Spring Framework you can do it with StringUtils:

public static String arrayToDelimitedString(Object[] arr)
public static String arrayToDelimitedString(Object[] arr, String delim)
public static String collectionToCommaDelimitedString(Collection coll)
public static String collectionToCommaDelimitedString(Collection coll, String delim)
1
  • Thanks, but how is it implemented?
    – 13ren
    Commented Mar 21, 2009 at 23:45
6

Based on Java's List toString implementation:

Iterator i = list.iterator();
for (;;) {
  sb.append(i.next());
  if (! i.hasNext()) break;
  ab.append(", ");
}

It uses a grammar like this:

List --> (Item , )* Item

By being last-based instead of first-based, it can check for skip-comma with the same test to check for end-of-list. I think this one is very elegant, but I'm not sure about clarity.

0
6

There is a pretty way to achieve this using Java 8:

List<String> list = Arrays.asList(array);
String joinedString = String.join(",", list);
1
  • TextUtils.join(",", list); Commented Jun 17, 2019 at 12:30
5
String delimiter = ",";
StringBuilder sb = new StringBuilder();
for (Item i : list) {
    sb.append(delimiter).append(i);
}
sb.toString().replaceFirst(delimiter, "");
4
for(int i=0, length=list.size(); i<length; i++)
  result+=(i==0?"":", ") + list.get(i);
3
  • Yes it's a bit cryptic, but an alternative to what's already been posted.
    – cherouvim
    Commented Mar 21, 2009 at 8:41
  • 1
    I think the code looks fine, IMHO its more pretty than your other answer and its hardly 'cryptic'. Wrap it up in a method called Join and your laughing, still I would expect the language to have a better way of solving what is really a common problem.
    – tarn
    Commented Mar 21, 2009 at 8:48
  • @tarn: you think it looks good because you have a Python/perl background ;) I like it as well
    – cherouvim
    Commented Mar 21, 2009 at 8:53
3

One option for the foreach loop is:

StringBuilder sb = new StringBuilder();
for(String s:list){
  if (sb.length()>0) sb.append(",");
  sb.append(s);
}
2
StringBuffer result = new StringBuffer();
for(Iterator it=list.iterator; it.hasNext(); ) {
  if (result.length()>0)
    result.append(", ");
  result.append(it.next());
}

Update: As Dave Webb mentioned in the comments this may not produce correct results if the first items in the list are empty strings.

7
  • meh.. still has the if in the loop.
    – sfossen
    Commented Mar 21, 2009 at 8:16
  • You can use a foreach loop to make it shorter. Commented Mar 21, 2009 at 8:37
  • That won't work if the first item in the list is an empty string.
    – David Webb
    Commented Mar 21, 2009 at 9:03
  • @Dave Webb: Yes, thanks. The question does not have such a requirement though.
    – cherouvim
    Commented Mar 21, 2009 at 9:08
  • @cherovium: The question doesn't say the none of the items will be the empty string so it's an implicit requirement. If you're creating a CSV file empty fields can be pretty common.
    – David Webb
    Commented Mar 21, 2009 at 9:13
2

I usually do this :

StringBuffer sb = new StringBuffer();
Iterator it = myList.iterator();
if (it.hasNext()) { sb.append(it.next().toString()); }
while (it.hasNext()) { sb.append(",").append(it.next().toString()); }

Though I think I'll to a this check from now on as per the Java implementation ;)

2
  • That's same logic as Sample 3, I like it because it does nothing unnecessary. However, I don't know if it is the clearest. BTW: it's slightly more efficient if you put the while inside the if, by avoiding two tests when the list is empty. It also makes it slighly clearer, to me.
    – 13ren
    Commented Mar 21, 2009 at 12:58
  • For heavens sake, use a StringBuilder
    – scravy
    Commented Nov 3, 2015 at 10:43
2

If you can use Groovy (which runs on the JVM):

def list = ['a', 'b', 'c', 'd']
println list.join(',')
1
  • thanks, but I'm interested in implementations. How is this one implemented?
    – 13ren
    Commented Mar 21, 2009 at 23:10
2

(Copy paste of my own answer from here.) Many of the solutions described here are a bit over the top, IMHO, especially those that rely on external libraries. There is a nice clean, clear idiom for achieving a comma separated list that I have always used. It relies on the conditional (?) operator:

Edit: Original solution correct, but non-optimal according to comments. Trying a second time:

int[] array = {1, 2, 3};
StringBuilder builder = new StringBuilder();
for (int i = 0 ;  i < array.length; i++)
       builder.append(i == 0 ? "" : ",").append(array[i]);

There you go, in 4 lines of code including the declaration of the array and the StringBuilder.

2nd Edit: If you are dealing with an Iterator:

    List<Integer> list = Arrays.asList(1, 2, 3);
    StringBuilder builder = new StringBuilder();
    for (Iterator it = list.iterator(); it.hasNext();)
        builder.append(it.next()).append(it.hasNext() ? "," : "");
7
  • This and stackoverflow.com/questions/668952/… above are similar. It's short and clear, but if you only have an iterator, you'd first need to convert. Inefficient, but maybe worth it for the clarity of this approach?
    – 13ren
    Commented Mar 21, 2009 at 23:09
  • Ugh, string concatenation creating a temporary StringBuilder within use of a StringBuilder. Inefficient. Better (more likes of Java, but better running code) would be "if (i > 0) { builder.append(','); }" followed by builder.append(array[i]);
    – Eddie
    Commented Mar 22, 2009 at 4:49
  • Yes, if you look in the bytecode, you are right. I can't believe such a simple question can get so complicated. I wonder if the compiler can optimize here. Commented Mar 22, 2009 at 5:01
  • Provided 2nd, hopefully better solution. Commented Mar 22, 2009 at 15:31
  • Might be better to split them (so people can vote on one or other).
    – 13ren
    Commented Mar 24, 2009 at 3:47
1

I usually use something similar to version 3. It works well c/c++/bash/... :P

1

I didn't compile it... but should work (or be close to working).

public static <T> String toString(final List<T> list, 
                                  final String delim)
{
    final StringBuilder builder;

    builder = new StringBuilder();

    for(final T item : list)
    {
        builder.append(item);
        builder.append(delim);
    }

    // kill the last delim
    builder.setLength(builder.length() - delim.length());

    return (builder.toString());
}
1
  • I like this way, i would just prefer an other formatting. But to mention one small fix: If the list is empty, this will throw an IndexOutOfBounds exception. So, either do a check before the setLength, or use Math.max(0,...)
    – tb-
    Commented Oct 29, 2012 at 19:16
1

This is very short, very clear, but gives my sensibilities the creeping horrors. It's also a bit awkward to adapt to different delimiters, especially if a String (not char).

for (Item i : list)
  sb.append(',').append(i);
if (sb.charAt(0)==',') sb.deleteCharAt(0);

Inspired by: Last iteration of enhanced for loop in java

1
StringBuffer sb = new StringBuffer();

for (int i = 0; i < myList.size(); i++)
{ 
    if (i > 0) 
    {
        sb.append(", ");
    }

    sb.append(myList.get(i)); 
}
3
  • I find this one to be very easy to embed into a static utility class, while being very easy to read and understand as well. It also does't require any extra variables or state other than the list itself, the loop and the delimiter. Commented Oct 9, 2011 at 9:56
  • This will provide something like: Item1Item2, Item3, Item4,
    – user1181445
    Commented Mar 12, 2013 at 20:48
  • For heavens sake, use a StringBuilder
    – scravy
    Commented Nov 3, 2015 at 10:41
1

I somewhat like this approach, which I found on a blog some time ago. Unfortunately I don't remember the blog's name/URL.

You can create a utility/helper class that looks like this:

private class Delimiter
{
    private final String delimiter;
    private boolean first = true;

    public Delimiter(String delimiter)
    {
        this.delimiter = delimiter;
    }

    @Override
    public String toString()
    {
        if (first) {
            first = false;
            return "";
        }

        return delimiter;
    }
}

Using the helper class is simple as this:

StringBuilder sb = new StringBuilder();
Delimiter delimiter = new Delimiter(", ");

for (String item : list) {
    sb.append(delimiter);
    sb.append(item);
}
1
  • Just a note: it should be "delimiter", not "delimeter".
    – Michael Myers
    Commented Mar 23, 2009 at 15:27
1

Because your delimiter is ", " you could use any of the following:

public class StringDelim {

    public static void removeBrackets(String string) {
        System.out.println(string.substring(1, string.length() - 1));
    }

    public static void main(String... args) {
        // Array.toString() example
        String [] arr = {"Hi" , "My", "name", "is", "br3nt"};
        String string = Arrays.toString(arr);
        removeBrackets(string);

        // List#toString() example
        List<String> list = new ArrayList<String>();
        list.add("Hi");
        list.add("My");
        list.add("name");
        list.add("is");
        list.add("br3nt");
        string = list.toString();
        removeBrackets(string);

        // Map#values().toString() example
        Map<String, String> map = new LinkedHashMap<String, String>();
        map.put("1", "Hi");
        map.put("2", "My");
        map.put("3", "name");
        map.put("4", "is");
        map.put("5", "br3nt");
        System.out.println(map.values().toString());
        removeBrackets(string);

        // Enum#toString() example
        EnumSet<Days> set = EnumSet.allOf(Days.class);
        string = set.toString();
        removeBrackets(string);
    }

    public enum Days {
        MON("Monday"),
        TUE("Tuesday"),
        WED("Wednesday"),
        THU("Thursday"),
        FRI("Friday"),
        SAT("Saturday"),
        SUN("Sunday");

        private final String day;

        Days(String day) {this.day = day;}
        public String toString() {return this.day;}
    }
}

If your delimiter is ANYTHING else then this isn't going to work for you.

1

I like this solution:

String delim = " - ", string = "";

for (String item : myCollection)
    string += delim + item;

string = string.substring(delim.length());

I assume it can make use of StringBuilder too.

1

In my opinion, this is the simplest to read and understand:

StringBuilder sb = new StringBuilder();
for(String string : strings) {
    sb.append(string).append(',');
}
sb.setLength(sb.length() - 1);
String result = sb.toString();
0

In Python its easy

",".join( yourlist )

In C# there is a static method on the String class

String.Join(",", yourlistofstrings)

Sorry, not sure about Java but thought I'd pipe up as you asked about other languages. I'm sure there would be something similar in Java.

5
  • IIRC, you get a trailing , in the .Net version. :-(
    – user52898
    Commented Mar 21, 2009 at 8:21
  • 1
    Just tested, no trailing delimiter in .NET or Python
    – tarn
    Commented Mar 21, 2009 at 8:25
  • 1
    thanks! I found the source for it: svn.python.org/view/python/branches/release22-branch/Objects/… search for "Catenate everything". It omits the separator for the last item.
    – 13ren
    Commented Mar 21, 2009 at 8:38
  • @13ren Nicely done! Does it help? I had a lock and quickly remembered why I choose not to program in C these days :P
    – tarn
    Commented Mar 21, 2009 at 8:43
  • @tarn, yeah, it's an interesting example because it only adds the comman if it is not the last item: if (i < seqlen - 1) { <add separator> }
    – 13ren
    Commented Mar 21, 2009 at 10:56
0

You can also unconditionally add the delimiter string, and after the loop remove the extra delimiter at the end. Then an "if list is empty then return this string" at the beginning will allow you to avoid the check at the end (as you cannot remove characters from an empty list)

So the question really is:

"Given a loop and an if, what do you think is the clearest way to have these together?"

0
public static String join (List<String> list, String separator) {
  String listToString = "";

  if (list == null || list.isEmpty()) {
   return listToString;
  }

  for (String element : list) {
   listToString += element + separator;
  }

  listToString = listToString.substring(0, separator.length());

  return listToString;
}
1
  • 1
    I think you meant to say listToString.substring(0, listToString.length()-separator.length());
    – 13ren
    Commented Sep 23, 2010 at 3:32
0
if (array.length>0)          // edited in response Joachim's comment
  sb.append(array[i]);
for (int i=1; i<array.length; i++)
  sb.append(",").append(array[i]);

Based on Clearest way to comma-delimit a list (Java)?

Using this idea: Does the last element in a loop deserve a separate treatment?

2
  • 1
    For this to work, you need to know that there is at least 1 element in the list, otherwise your first for-loop will crash with an IndexOutOfBoundsException. Commented Oct 9, 2011 at 10:03
  • @Joachim thanks, you're right of course. What an ugly solution I wrote! I'll change for (int i=0; i<1; i++) to if (array.length>0).
    – 13ren
    Commented Oct 10, 2011 at 18:45
0
public String toString(List<Item> items)
{
    StringBuilder sb = new StringBuilder("[");

    for (Item item : items)
    {
        sb.append(item).append(", ");
    }

    if (sb.length() >= 2)
    {
        //looks cleaner in C# sb.Length -= 2;
        sb.setLength(sb.length() - 2);
    }

    sb.append("]");

    return sb.toString();
}
1
  • 1
    Just noticed it's similar to the answer TofuBeer gave
    – Eblis
    Commented Nov 22, 2011 at 15:46
0

None of the answers uses recursion so far...

public class Main {

    public static String toString(List<String> list, char d) {
        int n = list.size();
        if(n==0) return "";
        return n > 1 ? Main.toString(list.subList(0, n - 1), d) + d
                  + list.get(n - 1) : list.get(0);
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList(new String[]{"1","2","3"});
        System.out.println(Main.toString(list, ','));
    }

}
0
0
private String betweenComma(ArrayList<String> strings) {
    String united = "";
    for (String string : strings) {
        united = united + "," + string;
    }
    return united.replaceFirst(",", "");
}
-1

Method

String join(List<Object> collection, String delimiter){
    StringBuilder stringBuilder = new StringBuilder();
    int size = collection.size();
    for (Object value : collection) {
        size --;
        if(size > 0){
            stringBuilder.append(value).append(delimiter);
        }
    }

    return stringBuilder.toString();
}

Usage

Given the array of [1,2,3]

join(myArray, ",") // 1,2,3

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