2

I'm learning about the StringBuider class. I have read in this site and many other books that when the compiler meets a '+' operator of literal, it automatically uses StringBuilder append's method to concatenate them.

It seems a little bit problematic since a StringBuilder object will be created at run time but the String reference is supposed to get the address of the concatenate String object already at compilation time.

String s1 = "hello";  
String s2 ="bc"; 
int value = 22;

When the compiler "meets" this code:

String s = s1+s2+22;

it "changes" it to:

String s = new StringBuilder().append("hello").append("bc").append(22).toString();

Maybe I am misunderstanding something?

Eitanos30
  • 1,331
  • 11
  • 19
  • 2
    _"When the compiler "meets" this code, it "changes" it to"_ -- No, this is incorrect. The two lines are completely different. There is no concatenation in the first one. – Jim Garrison Aug 14 '19 at 20:39
  • in the case of `String a = "a"; String b = "b"; String c = a+b;`, the concatonation is done at compile time since `a` and `b` are known at that time. – Benjamin Urquhart Aug 14 '19 at 20:44
  • @BenjaminUrquhart Not quite. That would require from `a` and `b` at `a+b` to be *constant variable* (declared as `final` and holding compile-time constant expression). Without it compiler will not assume any values for them so it will not do any concatenation for us and will leave it to be done at runtime via StringBuilder. – Pshemo Aug 14 '19 at 20:47
  • Code is taken from "Deital-Java How To Program" – Eitanos30 Aug 14 '19 at 20:51
  • @Pshemo my bad. Yes, it will only work for final variables – Benjamin Urquhart Aug 14 '19 at 20:51
  • @Eitanos30 Point is that your first example doesn't contain any `+` so there is no concatenation which means compiler doesn't need to generate any code involving `StringBuilder`. You probably missed line like `String s = s1 + s2 + value;`. – Pshemo Aug 14 '19 at 20:54
  • @Pshemo, Sorry i edited my post. Thanks, i didn't notice i forgot the most imortant detail. Can you please refer to the edited question? And also explain why what Benjamin Urquhart say isn't right? – Eitanos30 Aug 14 '19 at 21:01
  • "*It seems a little bit problematic since a StringBuilder object will be created at run time but the String reference is supposed to get the address of the concatenate String object already at compilation time.*" is confusing (or simply wrong). Can you explain what makes you think that "...the String reference is supposed to get the address of the concatenate String object already at compilation time"? (because it doesn't) – Pshemo Aug 14 '19 at 21:07
  • I don't see any other option that different reference will point on the same literal if it won't happen during compile time – Eitanos30 Aug 14 '19 at 21:08
  • I am not sure what you mean by "same literal". Same as which one? – Pshemo Aug 14 '19 at 21:11
  • If in code there are more than one appearance of the same literal, all reference gets the same address of the object that is created only once – Eitanos30 Aug 14 '19 at 21:14
  • You are probably thinking about String Pool. But that only involves String *literals* (written in code using double quotes like `"abc"`). For rest of strings like `System.out.print("Please state your name: "); String name = scanner.nextLine();` `"Please state your name: "` will be placed in String Pool, but value at `name` will be not (a) because it is not known at runtime (b) because there is no *need* to fill that pool with *all* strings - imagine application which reads terabytes of Stings each day have to cache them in RAM... It would not run very long and would need to restarted often. – Pshemo Aug 14 '19 at 21:25
  • Other case of string which would be placed in String Pool is when compiler *could* actually calculate result of concatenation because it *knows* all its operands (at compilation time). For instance if you have `"a"+"b"+1` then compiler can safely replace that *code* with `"ab1"` literal (which is result of that concatenation) and add it to constant pool. This question is related to that topic: [Comparing strings with == which are declared final in Java](https://stackoverflow.com/q/19418427) – Pshemo Aug 14 '19 at 21:32
  • @Pshemo, thanks. i'm trying to understand your explanation. I will also read the link you attached – Eitanos30 Aug 14 '19 at 21:49

1 Answers1

6

15.18.1. String Concatenation Operator +

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.

In your case,

String s1 = "hello";
String s2 ="bc";
int value = 22;

String r = s1 + s2 + value;

you will get

INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ILOAD 3
INVOKEVIRTUAL java/lang/StringBuilder.append (I)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;

While concatinating constant objects

String r = "hello" + "bc" + 22;

you will get

LDC "hellobc22"
ASTORE 2

When the compiler "meets" this code:

String s = s1+s2+22;

it "changes" it to:

String s = new StringBuilder().append("hello").append("bc").append(22).toString();

No. It may optimise it to

String s = new StringBuilder().append(s1).append(s2).append(value).toString();

but it can't replace s1 with "hello" because there is no guarantee the variable will keep referring to "hello". The variable is not final and thus open to reassignment.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • Thanks, but this explanation is too complicated for me. I can't understand it. If other users approved your response i will accept it cause i don't have the knowledge to understand it – Eitanos30 Aug 14 '19 at 21:07
  • @Eitanos30 No worries, I can elaborate on it. What exactly is unclear? – Andrew Tobilko Aug 14 '19 at 21:09
  • @ Andrew Tobikko, I don't know all the marks from the compiler you have attached – Eitanos30 Aug 14 '19 at 21:12
  • @Eitanos30 you don't have to. All it says is *"Create a new instance of `StringBuilder`, load a reference from a local variable on the stack and call `StringBuilder.append` (three times for `s1`, `s2`, and `value`)` and call `StringBuilder.toString`"* – Andrew Tobilko Aug 14 '19 at 21:30
  • @Eitanos30 it will be `new StringBuilder().append(s1).append(s2).append(value).toString()`. Note that I put the varibles instead the literals those varibles were assigned to. – Andrew Tobilko Aug 14 '19 at 21:35
  • Tobikko , Thanks. I need some time to understand it. Is it ok? – Eitanos30 Aug 14 '19 at 21:48
  • @Eitanos30 Sure, take your time. You can ask me later if something remains unclear. – Andrew Tobilko Aug 14 '19 at 21:56
  • Thanks. Can you please explain also the second compilation:(LINENUMBER...) – Eitanos30 Aug 14 '19 at 21:59
  • @Eitanos30 there is no variables involved. Constants can be concatenated at the compile time since they are known and they can't be changed. `LDC "hellobc22"` means *"push a dynamically-computed constant `"hellobc22"` onto the stack"* – Andrew Tobilko Aug 15 '19 at 06:33
  • @Eitanos30 `ASTORE 2` means *"store a reference from the stack into a local variable `r`* – Andrew Tobilko Aug 15 '19 at 06:34
  • @Eitanos30 more on bytecode instructions you can find here (https://docs.oracle.com/javase/specs/jvms/se12/html/jvms-2.html#jvms-2.11) and here (https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings) – Andrew Tobilko Aug 15 '19 at 06:36
  • @Tobiko. Thanks. I will read it. So i have some question in order to arrange things in my mind:1.Does the compiler uses StringBuilder class only when variable value is uknown? 2.In the first code, where is the command to store toString returned value in variable r? 3.About the second code, you wrote:LDC "hellobc22" means "push a dynamically-computed constant "hellobc22" onto the stack". Did you mean push the address of the new concatonation string address (which is placed in the string pool)? – Eitanos30 Aug 15 '19 at 12:39
  • In addition: 4.How can I understand from the compile result for the second code,that you have attached that variable are stored a reference to a place that is saved for the String pool? Shouldn’t we see a command that allocate place (like malloc in c) sets there the String content ,and then the allocated place is stored at the local variable r? 5.In addition which other choice to compile has (beside using the StringBuilder class) for concatenation strings? Could he use concat method of String class? – Eitanos30 Aug 15 '19 at 12:39
  • Note that starting with Java 9, string concatenation won’t use `StringBuilder` anymore. This demonstrates, that this internal isn’t relevant, all that matters, is the formal difference between compile-time constants (when concatenating compile-time constants) and runtime evaluation (when at least one argument is not a compile-time constant). – Holger Aug 16 '19 at 16:39
  • @Hogler, so how strings that are stored in variables (not pure literals) will concatentaion? via concat mehod of class String? – Eitanos30 Aug 17 '19 at 12:33
  • @Eitanos30 [This Q&A](https://stackoverflow.com/questions/46512888/how-is-string-concatenation-implemented-in-java-9) covers how strings are concatenated in Java 9. – Slaw Oct 27 '19 at 15:18