String vs StringBuffer. Tip of IDEA

462 views Asked by At

Intellij Idea offers to replace the following:

StringBuffer sb = new StringBuffer();
sb.append("Name=").append(name).append(", name2=").append(name2).append(", list=").append(list);
return sb.toString();

To:

return "name=" + name + ", name2=" + name2 + ", list=" + list;

As far as I know it's less effective (mutable/immutable). So, what's better?

2

There are 2 answers

1
JB Nizet On BEST ANSWER

The second one compiles to the same byte-code as the first one, except it uses a non-synchronized StringBuilder instead of a synchronized StringBuffer. So it's not only much more readable, but also slightly faster. I'd choose the second one.

Using a StringBuilder is useful when concatenating in a loop, to avoid creating many temporary String objects:

String result = "";
for (String element : array) {
    result += element;
}

should be replaced by

StringBuilder builder = new StringBuilder();
for (String element : array) {
    builder.append(element);
}
String result = builder.toString();
1
duffy356 On

The JavaCompiler changes concattenated Strings automatically to StringBuilders-> you can see them in the .class - Files.

So it will be the same for the java compiler.

The Tip appears to you, because IntelliJ assumes that the concatenatted strings are more easy to read for programmers.

Example: The toString-Method in the Editor:

XYZ.java:

public class XYZ {

    private String x;
    private int y;
    private Integer z;

    @Override
    public String toString() {
        return "XYZ [x=" + x + ", y=" + y + ", z=" + z + "]";
    }

}

The generated Byte Code of the toString-Method:

XYZ.class:

public toString()Ljava/lang/String;
   L0
    LINENUMBER 9 L0
    NEW java/lang/StringBuilder
    DUP
    LDC "XYZ [x="
    INVOKESPECIAL java/lang/StringBuilder.<init> (Ljava/lang/String;)V
    ALOAD 0
    GETFIELD at/gv/brz/jus3/as/dto/XYZ.x : Ljava/lang/String;
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    LDC ", y="
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ALOAD 0
    GETFIELD at/gv/brz/jus3/as/dto/XYZ.y : I
    INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
    LDC ", z="
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ALOAD 0
    GETFIELD at/gv/brz/jus3/as/dto/XYZ.z : Ljava/lang/Integer;
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder;
    LDC "]"
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    ARETURN
   L1
    LOCALVARIABLE this Lat/gv/brz/jus3/as/dto/XYZ; L0 L1 0
    MAXSTACK = 3
    MAXLOCALS = 1
}

As you can see, the compiler generates automatically a StringBuilder. So using explicity a StringBuilder is only necassary, if you generate it with the capacity parameter.