2

Is there any difference b/w 1 and 2 in terms of concatenation if i do it instance method. I mean in either case only one object will be constructed ultimately i.e "abc" .Yes only difference i see is test will lie inside permgen space even thread come out of instance method but x will be garbage collected once thread is out of method but in terms of number of objects constructred will be same. Right?

// option 1
String test="a"+"b"+"c";

// option 2  
StringBuffer x = new StringBuffer().append("a").append("b").append("c").toString()

I referred the link http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html to reach this conclusion.

Afshin Moazami
  • 2,092
  • 5
  • 33
  • 55
M Sach
  • 33,416
  • 76
  • 221
  • 314

6 Answers6

8

First notice that the documentation you have linked is very old. Notice it's for Java 1.4.2.

J2SE 1.4.2 is in its Java Technology End of Life (EOL) transition period. The EOL transition period began Dec, 11 2006 and will complete October 30th, 2008, when J2SE 1.4.2 will have reached its End of Service Life (EOSL).

In newer versions of the documentation this statement has been removed. However another statement has been added that you should be aware of:

As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.


Secondly notice that the documentation you refer to has this code:

x = "a" + 4 + "c";

The 4 there isn't just a typo. Your example is different because the compiler will convert the code to use just a single string literal. These two lines are the same:

x = "a" + "b" + "c"; 
x = "abc";

The string literal will be interned.


But in the general case where the compiler cannot just use a single string literal, the compiler will transform the first version into the second, except it will use StringBuilder instead because it is more efficient.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 1
    *"The compiler will transform the first version into the second"* I don't think it is the case. – assylias Jul 26 '12 at 10:40
  • But only in such simple scenario, right? If you have some logic between compiler will just keep doing "+" operator. – Michał Šrajer Jul 26 '12 at 10:41
  • 1
    Well yeah, in this simplified case it will just use a single string literal, but if he had variables... updated answer to make this clear. – Mark Byers Jul 26 '12 at 10:42
  • @ Mark . So in both options no memory will be allocated for temporary string literals "a","b","c". Right? – M Sach Jul 26 '12 at 10:54
  • @MSach With a StringBuffer, you create 3 string literals ("a", "b", "c") and a StringBuffer. With the first option, you only create one string literal: "abc" – assylias Jul 26 '12 at 10:55
  • @mark i am almost close. Now if i do String test1="a"+"b"+args[0]; where arg[0] is determined at run time. How many total object will be created in memory? As per my understanding one. becoz what ever the value of args[0] will be appended in the last of "ab". Will only one object be created. RIGHT? – M Sach Jul 26 '12 at 12:31
5

First of all - use StringBuilder instead of StringBuffer, StringBuffer is deprecated now.

And for your question, nowadays it doesn't really matter, compiler automacally transforms String concacenation to StringBuilder.

There are only two cases where to use it. First one is better code readability (for example if you are building long Strings like SQL queries). And second one, when you concanete Strings in the loop, compiler for always make a new StringBuilder instance for each walk through loop, so be carefull about that.

Petr Mensik
  • 26,874
  • 17
  • 90
  • 115
  • 3
    +1 While `StringBuffer` is not deprecated, it probably should be as there is almost never a good reason to use it except for legacy libraries which need it. e.g. it is used in SimpleDateFormat, a class which is not thread safe. ;) – Peter Lawrey Jul 26 '12 at 10:45
  • *"compiler automacally transforms String concacenation to StringBuilder"* except for string literals, which the case here. – assylias Jul 26 '12 at 10:47
  • Ok, sorry for misinterpretation :) – Petr Mensik Jul 26 '12 at 10:47
  • @assylias really?I thought that everything which is concacenated is transformed to StringBuilder. – Petr Mensik Jul 26 '12 at 10:51
4

First of all, StringBuilder is to StringBuffer what ArrayList is to Vector: it should be preferred because it's not synchronized.

Your first String is entirely constructed at compilation time, and is stored as a String literal. This literal is interned inside a pool, and the test variable always points to the same String instance.

Your second snippet dynamically concatenates, at runtime, three String literals. It returns a new String instance each time it's called.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I have two questions on this. If i make test=null will literal still reside in pool? Secondly you said "Your second snippet dynamically concatenates, at runtime, three String literals" but as per the link i mentioned it wont allocated any memory for tmporary string literal.This will be inserted in the last. Right? – M Sach Jul 26 '12 at 10:51
  • test = null just affects null to the variable. The string literal is unchanged. And it stays in the pool, yes. It will allocate memory for the StringBuilder and its internal fields, and for the new String instance created. The three literals are in the pool, and no additional memory is needed for them. – JB Nizet Jul 26 '12 at 11:40
  • The order does not matter. You have 4 literals in the pool: "abc", "a", "b", and "c". And the second snippet creates a StringBuffer + an additional String instance each time it's executed. – JB Nizet Jul 26 '12 at 16:12
  • i have posted a separate question for this at http://stackoverflow.com/questions/11673596/how-many-objects-will-be-created-during-this-string-operation – M Sach Jul 26 '12 at 16:18
4

Looking at the bytecode generated by the 2 examples, the first string is transformed into the "abc" string literal, whereas the second calls StringBuilder methods. You can actually test it with System.out.println(test == "abc");, which prints true.

   0: ldc           #2                  // String abc
   2: astore_1      
   3: new           #3                  // class java/lang/StringBuffer
   6: dup           
   7: invokespecial #4                  // Method java/lang/StringBuffer."<init>":()V
  10: ldc           #5                  // String a
  12: invokevirtual #6                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  15: ldc           #7                  // String b
  17: invokevirtual #6                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  20: ldc           #8                  // String c
  22: invokevirtual #6                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  25: invokevirtual #9                  // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
  28: astore_2      
assylias
  • 321,522
  • 82
  • 660
  • 783
3

In this specific case, where you're concatenating three string literals at compile time, the compiler will generate code just as if you'd typed:

String test="abc";

thus avoiding any intermediate objects altogether.

Graham Borland
  • 60,055
  • 21
  • 138
  • 179
  • so graham in both the cases no intermediate objects will be created right? – M Sach Jul 26 '12 at 11:00
  • Right, both `"a"+"b"+"c"` and `"abc"` are identical and produce no intermediate objects. – Graham Borland Jul 26 '12 at 11:03
  • Sorry graham i was not able to communicate to you.i was asking basically, will there be no intermediate objects also in second option in my post which is StringBuffer x = new StringBuffer().append("a").append("b").append("c").toString()? – M Sach Jul 26 '12 at 11:17
0

I think in case of memory usages both are same.

Pramod Kumar
  • 7,914
  • 5
  • 28
  • 37