23

I have the following code:

StringBuilder str = new StringBuilder("foo");
for(Field f : fields){
    str.append("|" + f);
}
str.append("|" + bar);
String result = str.toString();

I know compiler will optimize string concatenation "|" + f and replace it with StringBuilder. However will a new StringBuilder be created or the existing str will be used in Java 8? How about Java 9?

7
  • 7
    I'm not 100% sure here but I'd doubt str will be reused. Why don't you just use append("|").append(String.valueOf(f)) and be sure? Commented Jul 26, 2017 at 10:46
  • 1
    Most likely a new one. But you can easily test it be looking into the compiled code. Commented Jul 26, 2017 at 10:47
  • 1
    Pretty sure a new one will be used Commented Jul 26, 2017 at 10:47
  • 4
    @Thomas: there is no need for String.valueOf(…). Just append('|').append(f) will do. Commented Jul 26, 2017 at 11:53
  • 2
    By the way, see stackoverflow.com/questions/63150/… for better alternatives to replace your code. Commented Jul 26, 2017 at 17:50

3 Answers 3

23

By default in java-9 there will be no StringBuilder for string concatenation; it is a runtime decision how it's made via the invokedynamic. And the default policy is not a StringBuilder::append one.

You can also read more here.

Under java-8 a new one will be created (really easy to spot two occurrences of invokespecial // Method java/lang/StringBuilder."<init>":()V in the de-compiled bytecode.

Also, you have a suggestion about append.append...; just notice that this is much better than sb.append ... sb.append, and here is why.

Sign up to request clarification or add additional context in comments.

5 Comments

Do you have any link that specifies that? It will be great to read about that.
@Shirkam just search String concatenation java-9 and plenty of results should pop up (also see my edit).
@Shirkam read my other edit, that I think its pretty cool too.
Why did you link to that meta-question? It's just how to work with answers.
@Shirkam: like with lambda expressions, there is a visible impact in the API, which is already documented today
8

As String concatenation optimization is performed by the Java compiler, you can see what it does by decompiling the byte code:

$ cat Test.java
interface Field {}

public class Test {

    static String toString(Field[] fields, Object bar) {
        StringBuilder str = new StringBuilder("foo");
        for(Field f : fields){
            str.append("|" + f);
        }
        str.append("|" + bar);
        return str.toString();
    }
}
$ javac Test.java
$ javap -c Test.class
Compiled from "Test.java"
public class stackoverflow.Test {
  public stackoverflow.Test();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  static java.lang.String toString(stackoverflow.Field[], java.lang.Object);
    Code:
       0: new           #16                 // class java/lang/StringBuilder
       3: dup
       4: ldc           #18                 // String foo
       6: invokespecial #20                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
       9: astore_2
      10: aload_0
      11: dup
      12: astore        6
      14: arraylength
      15: istore        5
      17: iconst_0
      18: istore        4
      20: goto          53
      23: aload         6
      25: iload         4
      27: aaload
      28: astore_3
      29: aload_2
      30: new           #16                 // class java/lang/StringBuilder
      33: dup
      34: ldc           #23                 // String |
      36: invokespecial #20                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      39: aload_3
      40: invokevirtual #25                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      43: invokevirtual #29                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      46: invokevirtual #32                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      49: pop
      50: iinc          4, 1
      53: iload         4
      55: iload         5
      57: if_icmplt     23
      60: aload_2
      61: new           #16                 // class java/lang/StringBuilder
      64: dup
      65: ldc           #23                 // String |
      67: invokespecial #20                 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      70: aload_1
      71: invokevirtual #25                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      74: invokevirtual #29                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      77: invokevirtual #32                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      80: pop
      81: aload_2
      82: invokevirtual #29                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      85: areturn
}

As you can see, the code invokes StringBuilder constructors (Method java/lang/StringBuilder."<init>":) in 3 places, so new StringBuilders would be created in each iteration (unless the just-in-time compiler performs fancy optimization).

This is very unlikely to be a significant performance problem, but in the unlikely case it is you can easily fix this by rewriting to

str.append("|").append(f);

1 Comment

Though this optimization is most likely implemented by all relevant Java compilers, there is in general no strong guarantee for this behavior. The JLS for Java 8 states: "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."
0

As per the Java 9 API documentation

Implementation Note:

The implementation of the string concatenation operator is left to the discretion of a Java compiler, as long as the compiler ultimately conforms to The Java™ Language Specification. For example, the javac compiler may implement the operator with StringBuffer, StringBuilder, or java.lang.invoke.StringConcatFactory depending on the JDK version. The implementation of string conversion is typically through the method toString, defined by Object and inherited by all classes in Java.

According to this it will create a new String builder each iteration in your case. So, as mentioned by several people here, using the below code is more optimized

append("|").append(f)

You can find API Documentation here

3 Comments

why String.valueOf ?
"According to this" - how do you get that. This documentation explicitly doesn't say whether or how builders would be involved.
I agree with OrangeDog. There is no guarantee after all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.