Gaurav
Gaurav

Reputation: 309

Java Compiler replacing StringBuilder with + concatenation

Here's some simple Java code:

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

I compile it with JRE 1.6, and I observe the following in the decompiled class file:

String s = "a" + "b" + "c";

I had the following questions:

  1. Why does the compiler choose '+' over StringBuilder?
  2. Do we have any official Java specification that justifies this behavior?
  3. Does it really make sense to use StringBuilder in such cases, where we know compiler is going to change it anyway?

Upvotes: 4

Views: 4774

Answers (4)

Hearen
Hearen

Reputation: 7828

Just For Reference

Your questions have already been answered by Oliver Charlesworth but I think you are checking the wrong place to start this question.

You should check the ByteCode using javap -v YouClass.class instead of using the IDE to check the decompiled code which can be quite confusing.

The original java code

public class LockElimination {
    private static String concat(String s1, String s2, String s3) {
        return s1 + s2 + s3;
    }
}

The ByteCode generated by javap -v LockElimination.class

Constant pool:
   #1 = Methodref          #7.#16         // java/lang/Object."<init>":()V
   #2 = Class              #17            // java/lang/StringBuilder
   #3 = Methodref          #2.#16         // java/lang/StringBuilder."<init>":()V
   #4 = Methodref          #2.#18         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #5 = Methodref          #2.#19         // java/lang/StringBuilder.toString:()Ljava/lang/String;

Upvotes: 0

rgettman
rgettman

Reputation: 178253

  1. The decompiler must have assumed that the bytecode instructions to call append over and over resulted from source code that used the + operator.

  2. Section 15.18.1 of the JLS specifies that a compiler can use a StringBuffer or similar means to implement the + operator between Strings:

    An implementation may choose to perform conversion and concatenation in one step to avoid creating and then discarding an intermediate String object. To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.

    The StringBuilder class is a "similar technique".

  3. In this case, you can use either technique to concatenate your strings. If you have lots of complicated operations yielding strings that need to be concatenated, then you would be better off using a StringBuilder and appending them yourself.

Upvotes: 2

Kedar Mhaswade
Kedar Mhaswade

Reputation: 4695

I am not sure about JDK 1.6 (javac is part of JDK) but when I compile it with JDK 1.7, I get an appropriate disassembly.

The compilers are smart. In JDK, I think if you have s = "a" + "b" + "c" it will perhaps do it this way (use StringBuilder instead), but not the other way. More concretely, if all strings are compile-time constants (string literals) it will do even better -- calculate the string literal and replace the concatenation with that, so there will be less overhead at runtime.

Upvotes: 1

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272467

It's the other way round. + for String is implemented using StringBuilder (or StringBuffer) behind the scenes (see http://docs.oracle.com/javase/7/docs/api/java/lang/String.html or http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1).

Thus, once they're compiled, your two code snippets are indistinguishable. The decompiler has to make a guess at the original form.

Upvotes: 18

Related Questions