tags:

views:

5283

answers:

10

I'm curious and wasn't sure, so i thought id ask:

assuming String a and b.

a+=b
a.concat(b)

Under the hood are they the same thing?

Edit:

Here is concat decompiled as reference, I'd like to be able to decompile the + operator as well to see what that does, not sure how to do that yet.

   public String concat(String s)
    {
        int i = s.length();
        if(i == 0)
        {
            return this;
        } else
        {
            char ac[] = new char[count + i];
            getChars(0, count, ac, 0);
            s.getChars(0, i, ac, count);
            return new String(0, count + i, ac);


}
    }
+1  A: 

The + operator can work between a string and a string, char, integer, double or float data type value. It just converts the value to its string representation before concatenation.

The concat operator can only be done on and with strings. It checks for data type compatibility and throws an error if they don't match.

Except this, the code you provided do the same stuff.

Niyaz
+1  A: 

I don't think so. a.concat(b) is implemented in String and I think the implementation didn't change much since early java machines. The + operation implementation depends on java version and compiler. Currently + is implemented using StringBuffer to make the operation as fast as possible. Maybe in future this will change. In earlier versions of java + operation on Strings was much slower as it produced intermediate results. I guess that += is implemented using + and similarly optimized.

bibix
"Currently + is implemented using StringBuffer"FalseIt's StringBuilder. StringBuffer is the threadsafe impl of StringBuilder.
Frederic Morin
+10  A: 

Niyaz is correct, but it's also worth noting that the special + operator can be converted into something more efficient by the Java compiler. Java has a StringBuilder class which represents a non-thread-safe, mutable String. When performing a bunch of String concatenations, the Java compiler silently converts

String a = b + c + d;

into

String a = new StringBuilder(b).append(c).append(d).toString();

which for large strings is significantly more efficient. As far as I know, this does not happen when you use the concat method.

However, the concat method is more efficient when concatenating an empty String onto an existing String. In this case, the JVM does not need to create a new String object and can simply return the existing one. See the concat documentation to confirm this.

So if you're super-concerned about efficiency then you should use the concat method when concatenating possibly-empty Strings, and use + otherwise. However, the performance difference should be negligible and you probably shouldn't ever worry about this.

Eli Courtwright
concat infact doesn't do that. I've edited my post with a decompilation of the concat method
shsteimer
infact it does. Look a the first lines of your concat code. The problem with concat is that it always generates a new String()
Marcio Aguiar
+30  A: 

No, not quite.

Firstly, there's a slight difference in semantics. If a is null, then the latter NPEs but the former will treat the original value of a as if it were "null".

To look under the hood, write a simple class with a += b;

public class Concat {
    String cat(String a, String b) {
        a += b;
        return a;
    }
}

Now disassemble with javap -c (included in the Sun JDK). You should see a listing including:

java.lang.String cat(java.lang.String, java.lang.String);
  Code:
   0:   new     #2; //class java/lang/StringBuilder
   3:   dup
   4:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   7:   aload_1
   8:   invokevirtual   #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   11:  aload_2
   12:  invokevirtual   #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   15:  invokevirtual   #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/    String;
   18:  astore_1
   19:  aload_1
   20:  areturn

So, a += b is the equivalent of

a = new StringBuilder()
    .append(a)
    .append(b)
    .toString();

The concat method should be faster. However, with more strings the StringBuilder method wins, at least in terms of performance.

The source code of String and StringBuilder (and its package-private base class) is available in src.zip of the Sun JDK. You can see that you are building up a char array (resizing as necessary) and then throwing it away when you create the final String. In practice memory allocation is surprisingly fast.

Tom Hawtin - tackline
A: 

@Niyaz I know the result will be the same, im asking if under the hood they execute the same way.

@e-bartek Thanks, this is helpful. Do you happen to know what I can decompile to find how the + operator is implemented?

shsteimer
+1  A: 

How about some simple testing? Used the code below:

long start = System.currentTimeMillis();

String a = "a";

String b = "b";

for (int i = 0; i < 10000000; i++) { //ten million times
     String c = a.concat(b);
}

long end = System.currentTimeMillis();

System.out.println(end - start);

The "a + b" version runned in 2500ms. The a.concat(b) runned in 1200ms.

Tested several times. The concat version finished execution in an avarage half time.

This result surprised me because the concat method always creates a new string (it returns a "new String(result)". It's well know that:

String a = new String("a") // more than 20 times slower than String a = "a"

Why wasn't the compiler capable of optimize the string creation in "a + b" code, knowing the it always resulted in the same string? It could avoid a new string creation. If you don't believe the statement above, test for your self.

Marcio Aguiar
+3  A: 

Tom is correct in describing exactly what the + operator does. It creates a temporary StringBuilder, appends the parts, and finishes with toString().

However, all of the answers so far are ignoring the effects of HotSpot runtime optimizations. Specifically, these temporary operations are recognized as a common pattern and are replaced with more efficient machine code at run-time.

@marcio: You've created a micro-benchmark; with modern JVM's this is not a valid way to profile code.

The reason run-time optimization matters is that many of these differences in code -- even including object-creation -- are completely different once HotSpot gets going. The only way to know for sure is profiling your code in situ.

Finally, all of these methods are in fact incredibly fast. This might be a case of premature optimization. If you have code that concatenates strings a lot, the way to get maximum speed probably has nothing to do with which operators you choose and instead the algorithm you're using!

Jason Cohen
Thanks! I was not aware of the concept :)
Marcio Aguiar
I guess by "these temporary operations" you mean the use of escape analysis to allocate "heap" objects on the stack where provable correct. Although escape analysis is present in HotSpot (useful for removing some synchronisation), I don't believe it, is at the time of writing, u
Tom Hawtin - tackline
+8  A: 

I ran a similar test as @marcio but with the following loop instead:

String c = a;
for (long i = 0; i < 100000L; i++) {
    c = c.concat(b); // make sure javac cannot skip the loop
    // using c += b for the alternative
}

Just for good measure, I threw in StringBuilder.append() as well. Each test was run 10 times, with 100k reps for each run. Here are the results:

  • StringBuilder wins hands down. The clock time result was 0 for most the runs, and the longest took 16ms.
  • a += b takes about 40000ms (40s) for each run.
  • concat only requires 10000ms (10s) per run.

I haven't decompiled the class to see the internals or run it through profiler yet, but I suspect a += b spends much of the time creating new objects of StringBuilder and then converting them back to String.

sundae1888
A: 

@erickson StringBuilder does not collaborate with String to share the backing char array. Because of threading issues, this could allow you to create mutable Strings.

StringBuffer did share up to 1.4, but not since 5.0. Sharing has theoretical multi-threading problems. The 5.0 memory model (actually implemented by 1.4) adds final field semantics that correctly allow Strings to be immutable.

Tom Hawtin - tackline
Good catch, I hadn't looked at the implementation lately. Thanks for the pointer.
erickson
+1  A: 

Hi,
There is a big different in performance, you can see a deep analysis on StringBuilder, String.concat() and the "+" operator performance in my blog. Take a look at: http://blog.eyallupu.com/2010/09/under-hood-of-java-strings.html


Eyal

Eyal Lupu