0

Another question answered me how concatenation of String literals is evaluated in compile time. In a project I'm working on we handle multi-line Strings of big queries using a StringBuffer. It appends just literals, so it had me thinking whether if something similar might happen.

In the following code, will the buffer append its contents at compile time? how would this behave when multiple threads are trying to execute this function?

 public static String querySomething(int arg){


        StringBuffer buffer = new StringBuffer();
        buffer.append("A quite long query");
        buffer.append("that doesn't fit in one line");
        buffer.append("...");

  }

Wouldn't it be better to define the String as a constant since it would be thread safe and we know it can get concatenated at compile time with the plus operator. Something like:

  private final static REALLY_LONG_QUERY1 = "A quite long query that"
                                            +"doesn't fit in one line"
                                            +"...";
Community
  • 1
  • 1
Sednus
  • 2,095
  • 1
  • 18
  • 35
  • 2
    Since the `StringBuffer` is declared **inside the method** it won't come into account if this method is called by multiple threads at the same time. You can even replace it by `StringBuilder` and have the same behavior (with less overhead). – Luiggi Mendoza Apr 04 '13 at 13:47

4 Answers4

3

Wouldn't it be better to define the String as a constant ...

Basically, yes.

... since it would be thread safe and we know it can get concatenated at compile time with the plus operator.

These assertions are both correct.

However, you would not need to worry about thread safety any in the version of your code with a StringBuffer.

  • The StringBuffer class is thread-safe.
  • If the StringBuffer instance is only visible to one thread (e.g. the thread calling the method that declares and uses the instance), then the instance is thread confined and does not need to be a thread-safe data structure. (And you could use StringBuilder instead ...)

The primary advantage of the version that uses + concatenation of literals is that it takes zero time at runtime, and causes no allocation of objects ... apart from the one String object that represents the concatenated string constant that is allocated when your class is loaded.


In fact, in many places where people explicitly use StringBuilder or StringBuffer to "optimize" string concatenation, it either has no effect, or actually makes the code slower:

  • As you noted, the Java compiler evaluates concatenation of literals (using +) at compiler time, but it can't do the same thing for explicit StringBuilder.append calls.

  • In addition, the Java compiler will typically translate non-constant String concatenations (using +) in an expression into equivalent code using StringBuilder.

The only cases where it is worthwhile to use StringBuilder explicitly are when the sting building spans multiple statements; e.g. because you are concatenating stuff in a loop.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I'm not worried about thread safety because I know that `StringBuffer` is thread-safe but would that mean that more memory will be allocated? One new instance per thread? – Sednus Apr 04 '13 at 13:56
  • The StringBuffer version allocates a new StringBuffer object each time it is run ... unless you try to reuse an existing object. (And if you do that, you do need to worry about multi-threading ...) – Stephen C Apr 04 '13 at 13:59
  • So, will the contents of `StringBuffer` be concatenated at compile time or not? – Sednus Apr 04 '13 at 14:08
  • 1
    No it won't. The `StringBuffer.append` calls cannot be combined by the javac compiler, and I doubt that the JIT compiler will do it either. – Stephen C Apr 04 '13 at 14:17
1

I would prefer the second solution (merely using + operator).

Why? Because:

  • More readable
  • More functional (oriented functional programming, fashion and efficient today) avoiding useless (temporary) local variables and especially mutable variables (like buffer is).
Mik378
  • 21,881
  • 15
  • 82
  • 180
0

In the following code, will the buffer append its contents at compile time?

Yes.

How would this behave when multiple threads are trying to execute this function?

No problems, since each thread would use it's own StringBuffer (it is declared inside the method).

Wouldn't it be better to define the String as a constant?

Yes, it would make more sense here.

Keppil
  • 45,603
  • 8
  • 97
  • 119
  • In the presented case, the thread-safety offered by `StringBuffer` doesn't come into account since your first statement: *each thread would use it's own `StringBuffer`*. – Luiggi Mendoza Apr 04 '13 at 13:50
  • StringBuffer thread safety is irrelevant - the variable is declared inside the method body, hence it lives and is accessible only in that method in that thread (unless passed further, etc). – Dariusz Apr 04 '13 at 13:50
  • By each thread would use it's own `StringBuilder` does that mean that I will allocate a new `StringBuffer` per thread? How does that compare to the other alternative? – Sednus Apr 04 '13 at 13:50
  • I know that the thread safety of `StringBuffer` doesn't come into play here, but figured I could add that info too. Nevermind, deleted the extraneous information. – Keppil Apr 04 '13 at 13:52
  • @Sednus: Yes, therefore it makes more sense to use a constant in your example. – Keppil Apr 04 '13 at 13:54
0

StringBuffer fit better when you want to build a string which you don't know the actual size at compile time, for example:

public static String querySomething(int arg) {
    StringBuffer buffer = new StringBuffer();
    while (...) {
       buffer.Append(someStuff());
    }
}

In your case, a constant is more suitable.

Anthony Garcia-Labiad
  • 3,531
  • 1
  • 26
  • 30