30

I'm working on a server that returns character separated lists to its client. In order to build these lists I have to detect the first iteration through a for-each loop:

    StringBuilder builder = new StringBuilder() ;
    boolean firstIterationFlag = true ;

    for ( String s : list ){
        if ( firstIterationFlag) {
            firstIterationFlag = false ;
        } else {
            builder.append(separator);
        }
        builder.append(s) ;         
   }
   return builder.toString() ;

Is there a way of doing this without the flag?

Don Branson
  • 13,631
  • 10
  • 59
  • 101
user903724
  • 2,956
  • 4
  • 24
  • 27
  • Why do you have to detect the first iteration of the loop? – BeRecursive May 08 '12 at 16:26
  • instead of a `forEach` loop, you could manually do a normal `for` loop, starting with index `1` instead of 0. – Sheriff May 08 '12 at 16:26
  • 2
    Have a look at this SO question: http://stackoverflow.com/questions/63150/whats-the-best-way-to-build-a-string-of-delimited-items-in-java - it may be a better solution that yours. – Aleks G May 08 '12 at 16:27
  • ...or user list.indexOf(s) to get index... – viliam May 08 '12 at 16:27
  • 1
    @vilo: that is potentially a linear-time hit to each iteration, so a O(n^2) hit to the routine just to glue some text together. – andersoj May 08 '12 at 16:29
  • @andersoj: you're right. I didn't think about that. I thought it's about code polishing (small string collections). `org.apache.commons.StringUtils.join()` looks good. – viliam May 08 '12 at 16:41

9 Answers9

21

One simpler way for this situation is to note that you can always append an empty string:

// For the first iteration, use a no-op separator
String currentSeparator = "";
for (String s : list) {
    builder.append(currentSeparator);
    builder.append(s);
    // From the second iteration onwards, use this
    currentSeparator = separator;
}

Alternatively (and preferrably) use Guava's Joiner class to start with :)

This "joiner" scenario is almost always the one given for this requirement - so just use Joiner. For other scenarios, either use a regular for loop or use the condition as per your code.

Jérôme B
  • 420
  • 1
  • 6
  • 25
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
9

Not using foreach, but by using the iterator manually:

Iterator<String> it = list.iterator();
if(it.hasNext()){
    doSomeThingForTheFirstTime(it.next());
    while(it.hasNext()){
        doSomethingElse(it.next);
    }
}

(btw, this is pretty much what Guava's Joiner class does internally, though on a higher level)

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
3

In the specific case you cite, use Guava's Joiner instead of rolling your own...

An object which joins pieces of text (specified as an array, Iterable, varargs or even a Map) with a separator. It either appends the results to an Appendable or returns them as a String. Example:

Joiner joiner = Joiner.on(separator).skipNulls();
return joiner.join(list);
AJPerez
  • 3,435
  • 10
  • 61
  • 91
andersoj
  • 22,406
  • 7
  • 62
  • 73
3

Java 8 Solution

If you have Java 8 available, you can simply use String#join, no need for Guava:

String.join(", ", list)
amoebe
  • 4,857
  • 5
  • 37
  • 42
1

Just for the fun here is a different option.

    StringBuilder builder = new StringBuilder();
    for (String s : list) {
        builder.append(separator);
        builder.append(s);
    }
    builder.deleteCharAt(0);
    return builder.toString();
Krrose27
  • 1,026
  • 8
  • 13
1

You can try this :)

int i = 0;
for (something : manythings) {
    i++;
}
He Yifei 何一非
  • 2,592
  • 4
  • 38
  • 69
0

I would use commons.lang StringUtils.join function (see http://commons.apache.org/lang/api-2.4/org/apache/commons/lang/StringUtils.html). I strongly recommend that you get acquainted with this and other helper libraries to avoid re-inventing the wheel.

Pierre
  • 1,329
  • 2
  • 12
  • 21
0

You could also use the following method:

public static String toString(List<?> list, String separator) {
    StringBuilder sb = new StringBuilder();
    Iterator<?> it = list.iterator();
    while (it.hasNext()) {
        Object next = it.next();
        sb.append(next);
        if (it.hasNext()) {
            sb.append(separator);
        }
    }
    return sb.toString();
}

The enhanced for statement is equivalent to a basic for statement of the form:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
    VariableModifiersopt TargetType Identifier =
        (TargetType) #i.next();
    Statement
}

#i is an automatically generated identifier

Paul Vargas
  • 41,222
  • 15
  • 102
  • 148
0

Well, this will not detect the first iteration in the loop, but solve the problem. Just append the seperator at the end of each string and cut off the last seperator.

StringBuilder builder = new StringBuilder() ;

for ( String s : list ) {
    builder.append(s) ;         
    builder.append(separator);
}
builder.setLength(builder.length() - separator.length());
return builder.toString() ;
Peter
  • 1