6

I was having a discussion about usage of Strings and StringBuffers in Java. How many objects are created in each of these two examples?

Ex 1:

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

Ex 2:

StringBuilder sb = new StringBuilder("a"); sb.append("b"); sb.append("c"); 

In my opinion, Ex 1 will create 5 and Ex 2 will create 4 objects.

6
  • 2
    The first example will create 1 object as the compiler can optimise it. Commented May 4, 2012 at 6:08
  • 1
    Example 1 generates this: String s = "a"; s = (new StringBuilder(String.valueOf(s))).append("b").toString(); s = (new StringBuilder(String.valueOf(s))).append("c").toString(); System.err.println(s);. It looks like javac is not optimizing that (at least in Java 6) Commented May 4, 2012 at 6:15
  • It should do it if it was: "a" + "b" + "c". I'm surprised the other case isn't optimised too. But oh well ... See: nicklothian.com/blog/2005/06/09/on-java-string-concatenation Commented May 4, 2012 at 6:19
  • First example, Optimized? I thought all strings are unique and immutable so shouldn't it be 5 objects regardless of optimization? Commented May 4, 2012 at 6:24
  • 1
    @Thihara: not if the Javac (rather than JIT) compiler gets in there first. Commented May 4, 2012 at 6:26

4 Answers 4

6

I've used a memory profiler to get the exact counts.

On my machine, the first example creates 8 objects:

String s = "a"; s = s + "b"; s = s + "c"; 
  • two objects of type String;
  • two objects of type StringBuilder;
  • four objects of type char[].

On the other hand, the second example:

StringBuffer sb = new StringBuffer("a"); sb.append("b"); sb.append("c"); 

creates 2 objects:

  • one object of type StringBuilder;
  • one object of type char[].

This is using JDK 1.6u30.

P.S. To the make the comparison fair, you probably ought to call sb.toString() at the end of the second example.

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

10 Comments

is this machine/compiler-dependent?
@AlexLockwood: Probably JDK-dependent to some extent, although I'd be quite surprised if there was much variability across recent JDKs.
It seems rather silly to distinguish between a char[] and it's String abstraction in a high-level language like Java :P. But I agree it is correct to do so (not silly on your part... just silly in a kind of stupid example like this one).
@AlexLockwood: I actually think it's very important to account for sub-objects (such as the char[]s in this example). Without this, the counts are largely meaningless: one can always wrap an arbitrary amount of complexity into a single object, and claim there's only one (top-level) new.
@GuillaumePolet: Of course char[] is an object. All Java arrays are. If you don't believe me, try new char[0].getClass(), or see stackoverflow.com/questions/2009210/…
|
5

In terms of objects created:

Example 1 creates 8 objects:

String s = "a"; // No object created s = s + "b"; // 1 StringBuilder/StringBuffer + 1 String + 2 char[] (1 for SB and 1 for String) s = s + "c"; // 1 StringBuilder/StringBuffer + 1 String + 2 char[] (1 for SB and 1 for String) 

Example 2 creates 2 object:

StringBuffer sb = new StringBuffer("a"); // 1 StringBuffer + 1 char[] (in SB) sb.append("b"); // 0 sb.append("c"); // 0 

To be fair, I did not know that new char[] actually created an Object in Java (but I knew they were created). Thanks to aix for pointing that out.

1 Comment

He/she could have run the test procedure in another JDK version and obtained different results.
4

You can determine the answer by analyzing the java bytecode (use javap -c). Example 1 creates two StringBuilder objects (see line #4) and two String objects (see line #7), while example 2 creates one StringBuilder object (see line #2).

Note that you must also take the char[] objects into account (since arrays are objects in Java). String and StringBuilder objects are both implemented using an underlying char[]. Thus, example 1 creates eight objects and example 2 creates two objects.

Example 1:

public static void main(java.lang.String[]); Code: 0: ldc #2; //String a 2: astore_1 3: new #3; //class java/lang/StringBuilder 6: dup 7: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V 10: aload_1 11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: ldc #6; //String b 16: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_1 23: new #3; //class java/lang/StringBuilder 26: dup 27: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V 30: aload_1 31: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 34: ldc #8; //String c 36: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 39: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 42: astore_1 43: return } 

Example 2:

public static void main(java.lang.String[]); Code: 0: new #2; //class java/lang/StringBuilder 3: dup 4: ldc #3; //String a 6: invokespecial #4; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 9: astore_1 10: aload_1 11: ldc #5; //String b 13: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 16: pop 17: aload_1 18: ldc #7; //String c 20: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 23: pop 24: return } 

1 Comment

I have a little doubt. , oracle docs here docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html says this about append: "public StringBuilder append(Object obj) Appends the string representation of the Object argument. The overall effect is exactly as if the argument were converted to a string by the method String.valueOf(Object), and the characters of that string were then appended to this character sequence." Doesn't that mean objects will be created for String literals.
-1

The answer is tied to specific implementations of the language (compiler and runtime libraries). Even to the presence of specific optimization options or not. And, of course, version of the implementation (and, implicitly, the JLS it is compliant with). So, it's better to speak in term of minima and maxima. In fact, this exercise gives a better

For Ex1, the minimum number of objects is 1 (the compiler realizes that there are only constants involved and produces only code for String s= "abc" ; ). The maximum could be just anything, depending on implementation, but a reasonable estimation is 8 (also given in another answer as the number produced by certain configuration).

For Ex2, the minimum number of objects is 2. The compiler has no way of knowing if we have replaced StringBuilder with a custom version with different semantics, so it will not optimize. The maximum could be around 6, for an extremely memory-conserving StringBuilder implementation that expands a backing char[] array one character at a time, but in most cases it will be 2 too.

1 Comment

The compiler 'produces code for String s = "abc";', but this does not create an object when executed, so the minum is actually zero.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.