views:

464

answers:

8

Let's say I have two char variables, and later on I want to concatenate them into a string. This is how I would do it:

char c1, c2;
// ...

String s = "" + c1 + c2;

I've seen people who say that the "" + "trick" is "ugly", etc, and that you should use String.valueOf or Character.toString instead. I prefer this construct because:

  • I prefer using language feature instead of API call if possible
    • In general, isn't the language usually more stable than the API?
    • If language feature only hides API call, then even stronger reason to prefer it!
      • More abstract! Hiding is good!
  • I like that the c1 and c2 are visually on the same level
    • String.valueOf(c1) + c2 suggests something is special about c1
  • It's shorter.

Is there really a good argument why String.valueOf or Character.toString is preferrable to "" +?


Trivia: in java.lang.AssertionError, the following line appears 7 times, each with a different type:

    this("" + detailMessage);
+2  A: 

I think that in "" + var the + is actually overloaded to make the conversion:

The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method. String conversions are implemented through the method toString, defined by Object and inherited by all classes in Java. For additional information on string concatenation and conversion

So no difference and no problem from a technical point of view.

Form a readability point of view - it's a matter of personal preference or agreed coding style within the team.

Bozho
I just added the [coding-style] tag to the question; that's what this is mostly about.
polygenelubricants
+14  A: 

Your arguments are good; this is one of the more expressive areas of the Java language, and the "" + idiom seems well entrenched, as you discovered.

See String concatenation in the JLS. An expression like

"" + c1 + c2

is equivalent to

new StringBuffer().append(new Character(c1).toString())
                  .append(new Character(c2).toString()).toString()

except that all of the intermediate objects are not necessary (so efficiency is not a motive). The spec says that an implementation can use the StringBuffer or not. Since this feature is built into the language, I see no reason to use the more verbose form, especially in an already verbose language.

jleedev
Actually, no. The JLS explains it this way, but the compiler implements it differently.The Eclipse compiler produces bytecode equivalent to new StringBuilder().append(c1).append(c2).toString()The javac compiler (1.5) produces bytecode equivalent to new StringBuilder().append("").append(c1).append(c2).toString()
Christian Semrau
+10  A: 

The problem with that construct is that it usually doesn't express the intent.

It represents concatenation of a String with another value, but concatenation is not usually the goal of this line.

In the specific case that you demonstrated, concatenation is actually the goal, so this code does express the intent.

In the more common use of this approach (String s = "" + intValue;), the concatentation is merely a tolerated side-effect, while the conversion of intValue is the actual goal. And a simple String.valueOf(intValue) expresses that intent much clearer.

Joachim Sauer
I don't think so. `"" + x` is extremely common, the intent should be clear.
mafutrct
+1 for good argument; still disagree, though.
polygenelubricants
@mafutrct: if the intent is only clear when you've seen that exact construct many times before, then it isn't clear as such. It only proves that pattern recognition works.
Joachim Sauer
@polygenelubricants: fair enough!
Joachim Sauer
I would argue that nearly every java programmer has seen that exact construct many times before, as it's probably one of the first things they learn. For the ones who haven't, they're definitely going to see it many times in the future and will probably catch on quick.
Chris
@Chris: don't underestimate the number of inexperienced developers out there and how many of them have to maintain existing code.
Joachim Sauer
@Chris: let me try to rephrase your argument: "It's not ugly, because it's common." That doesn't sound right to me.
Joachim Sauer
I didn't say it wasn't ugly. More like "It's incredibly common and probably not going to go away."
Chris
@Chris: then I misread your comment, sorry. But does that mean that it should be used?
Joachim Sauer
I think you've already given a very suitable answer to that question :)
Chris
+1  A: 

The main problem is simply performance issues: if your code is in a loop that will be run billions of times, you almost certainly will not want to use ""+a+b, since, as stated in jleedev's answer this is equivalent to

 new StringBuffer().append(new Character(a).toString())
                   .append(new Character(b).toString()).toString();

....but if you're using it in a unit test or a part of your code that isn't performance-critical, I fully agree that it's shorter and easier.


OK so here is a simple test I came up with to prove my point:

    char a = 'a';
    char b = 'b';

    long l = 0;
    long currenttime = System.nanoTime();
    for(int i=0; i<10000000; i++) {
        l += (""+a+b).length();
    }
    long time = System.nanoTime() - currenttime;
    System.out.println("result: "+l+" after "+time+" ns.");

    l = 0;
    currenttime = System.nanoTime();
    StringBuilder sb = new StringBuilder();
    for(int i=0; i<10000000; i++) {
        sb.setLength( 0 );
        sb.append( a );
        sb.append( b );
        l += sb.toString().length();
    }
    time = System.nanoTime() - currenttime;
    System.out.println("result: "+l+" after "+time+" ns.");

Result:

 result: 20000000 after 712920887 ns.
 result: 20000000 after 360849170 ns.
Epaga
-1: The alternatives will end up *doing the same thing*!
Michael Borgwardt
if you are going to claim performance issues, you better show the exact difference between the both options.
NomeN
@Michael @NomeN there ya go, guys
Epaga
Of course #2 is faster: Only one StringBuilder is created, while #1 creates 10000000 StringBuilders. But that wasn't the point: To show which one of the alternatives is faster, you should have used String.valueOf(a) + String.valueOf(b) in the second loop, which would also have caused the creation of a new StringBuilder in each invocation of the loop.
FRotthowe
If you're going for a fast alternative over readability, you're going to be using a StringBuilder. String.valueOf(a)+String.valueOf(b) is a bad idea, it's more verbose and is actually twice as slow as ""+a+b.
Epaga
@Epaga: so your argument is basically don't use `+` at all? Always use `StringBuilder` manually? No one would question that that is going to be faster, but that's an entirely different subject than what we're talking about.
polygenelubricants
@polygenelubricants No, my argument is: use `+`-concatenation if performance is not a critical issue (which is 95% of the time). Otherwise, use `StringBuilder`.
Epaga
+2  A: 

In my opinion, "" + x is very readable, short, and precise to the point. I'd prefer it to longer constructs like String.valueOf. The behavior is well defined and it's so commonly in use that I find it hard to call it a hack at all.

The only thing I'd be slightly worried about is performance - and am very positive that it does not matter usually (even though I did not measure or look at the binary). There is also a fair chance that this kind of concat is optimized away, since it should be easy to detect it (this is just a guess though).

mafutrct
it matters greatly if your code is run hundreds of thousands of times in a loop.
Epaga
Nobody would use this in a loop - in loops you're always using the most well known performant code. In 99% of all cases, it's not a problem. Readability in the general case is far more important, imo.
mafutrct
+1  A: 

Unless your app needs every ounce of performance, write the code that's quicker to write and easier to read. "" + is a slower-to-execute syntax, but it certainly seems easier to read every time I've used it.

Dean J
+1  A: 

What about

new String(new char[] {a, b})

and if you do it alot you could create a class "Strings" with:

public static String valueOf(char... chars) {
    return new String(chars);
}

Your line would then read

String s = Strings.valueOf(a, b);

Nice and short.

Edited

A better name might be:

String s = Chars.asString(a, b);
Willi
Should also be very fast, as the only thing that has to be done is an array copy which is quite fast.
Willi
that's a good alternative.
Epaga
-1 nobody Can tell what this does without looking at the method called. Please refactor!
Thorbjørn Ravn Andersen
@Thorbjørn: Any suggestions? *Constructive* criticism is always welcome.
Willi
I would probably name the class CharHelper (CharUtils is another candidate) and the method charsToString, making the line `String s = CharHelper.charsToString(a, b)`
Thorbjørn Ravn Andersen
A javadoc comment would be sufficient in my opinion. There are a lot of methods in the jdk which are useless without description. Having a method in a class called Strings which takes a char array and produces a String seems relatively straight forward to me. You suggestion is too verbose. Chars.asString(char... chars)might be a good alternative.
Willi
+1  A: 

I prefer using String.valueOf for single conversions - but in your case you really want concatenation.

However, I would suggest that this version would remove all potential ambiguity:

String s = c1 + "" + c2;

That way there's no possibility, however remote, of someone considering whether c1 and c2 will be added together before the concatenation.

Jon Skeet