3

I need to build a pattern string according to an argument list. If the arguments are "foo", "bar", "data", then pattern should be: "?, ?, ?"

My code is:

List<String> args;
...
for(String s : args) {
  pattern += "?,";
}
pattern = pattern.substring(0, pattern.length()-1);

It works fine, the only concern is, s is not used, it seems the code is a little dirty.

Any improvements for this?

I hope something like:

for(args.size()) {
    ...
}

But apparently there isn't..

Deqing
  • 14,098
  • 15
  • 84
  • 131
  • 1
    Off topic: If you add `,?` instead of `?,` and change `pattern.substring(0, pattern.length()-1)` to `pattern.substring(1)` it might be slightly faster and easier to read – Daniel Alder Mar 24 '14 at 12:33

7 Answers7

3

You could use the class for loop with conditions:

for (int i = 0, s < args.size(); i++)

In this case, i is being used as a counting variable.

Other than that, there aren't any improvements to be made, although there isn't a need for improvements.

Michael Yaworski
  • 13,410
  • 19
  • 69
  • 97
  • 2
    Maybe it is no such "improvements" available, but eclipse complains of unused variable, which annoys me a little. Is it fine if I add `@SuppressWarnings("unused")` in this case? – Deqing Oct 21 '13 at 05:30
2

I usually do that in Haskell / Python style - naming it with "_". That way it's sort of obvious that variable is intentionally unused:

int n = 0;
for (final Object _ : iterable) { ++n; }

IntelliJ still complains, though :)

wonder.mice
  • 7,227
  • 3
  • 36
  • 39
1

Another option is to use the Java Stream's api. It's pretty neat.

String output = args
            .stream()
            .map( string -> "?" ) // transform each string into a ?
            .collect( Collectors.joining( "," ) ); // collect and join on ,
RobOhRob
  • 585
  • 7
  • 17
0

Why not use for (int i = 0; i < args.size(); i++) { ... }

You use the for each block if you want to make use of the contents of whatever you iterate on. For example, you use for (String s : args) if you know you're going to use each String value present in args. And it looks like here, you don't need the actual Strings.

Shobit
  • 776
  • 1
  • 6
  • 20
  • 1
    Maybe I'm splitting hair here, for me this classic for loop just not concise as for-each loop. – Deqing Oct 21 '13 at 05:50
0

I would suggest using StringBuilder along with the classic for loop here.

String pattern = "";
if (args.size() > 0) {
    StringBuilder sb = new StringBuilder("?");
    for(int i = 1; i < args.size(); i++) {
        sb.append(", ?");
    }
    pattern = sb.toString();
}


If you don't want to use a for loop (as you stated not concise enough) use a while instead:
int count;
String pattern = "";
if ((count = args.size()) > 0) {
    StringBuilder sb = new StringBuilder("?");
    while (count-- > 1) {
        sb.append(", ?");
    }
    pattern = sb.toString();
}

Also, see When to use StringBuilder?

At the point where you're concatenating in a loop - that's usually when the compiler can't substitute StringBuilder by itself.

Community
  • 1
  • 1
Ravi K Thapliyal
  • 51,095
  • 9
  • 76
  • 89
  • Any particular reason to prefer `StringBuilder` over `String` in this case? – Deqing Oct 21 '13 at 05:44
  • @Deqing Take a look at [When to use StringBuilder](http://stackoverflow.com/q/4645020/1237040) and this [answer](http://stackoverflow.com/a/1532483/1237040). Also, updated my answer to use a `while` instead of `for` you don't seem to want. – Ravi K Thapliyal Oct 21 '13 at 07:11
0

If you have Guava around, you could try combining Joiner with Collections.nCopies:

Joiner.on(", ").join(Collections.nCopies(args.size(), "?"));
Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
  • Thanks, very powerful, though it seems I can't introduce `Guava` to my project at the moment. – Deqing Oct 21 '13 at 05:46
0

What you're looking for is a concept known as a "join". In stronger languages, like Groovy, it's available in the standard library, and you could write, for instance args.join(',') to get what you want. With Java, you can get a similar effect with StringUtils.join(args, ",") from Commons Lang (a library that should be included in every Java project everywhere).

Update: I obviously missed an important part with my original answer. The list of strings needs to be turned into question marks first. Commons Collections, another library that should always be included in Java apps, lets you do that with CollectionUtils.transform(args,new ConstantTransformer<String, String>("?")). Then pass the result to the join that I originally mentioned. Of course, this is getting a bit unwieldy in Java, and a more imperative approach might be more appropriate.

For the sake of comparison, the entire thing can be solved in Groovy and many other languages with something like args.collect{'?'}.join(','). In Java, with the utilities I mentioned, that goes more like:

StringUtils.join(
    CollectionUtils.transform(args, 
                              new ConstantTransformer<String, String>("?")),
    ",");

Quite a bit less readable...

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • Thanks for introducing `join`. But looks like it can't be applied to my case. I'd like to have `"?, ?, ?"`, while `join` returns `"foo,bar,data"` – Deqing Oct 21 '13 at 05:26