When to Use Stringbuilder

When to use StringBuilder in Java

If you use String concatenation in a loop, something like this,

String s = "";
for (int i = 0; i < 100; i++) {
s += ", " + i;
}

then you should use a StringBuilder (not StringBuffer) instead of a String, because it is much faster and consumes less memory.

If you have a single statement,

String s = "1, " + "2, " + "3, " + "4, " ...;

then you can use Strings, because the compiler will use StringBuilder automatically.

When to use StringBuilder?

I warmly suggest you to read The Sad Tragedy of Micro-Optimization Theater, by Jeff Atwood.

It treats Simple Concatenation vs. StringBuilder vs. other methods.

Now, if you want to see some numbers and graphs, follow the link ;)

When should you explicitly use a StringBuilder?

It's more general than "inside loops" - it's any time you want to do concatenation over multiple statements, and don't need the intermediate result as a string. For example:

StringBuilder builder = new StringBuilder("Start");
if (someCondition) {
builder.append("Foo");
}
if (someOtherCondition) {
builder.append("Bar");
}
builder.append("End");
String result = builder.toString();

While you could write that as:

String result = "Start" + (someCondition ? "Foo" : "")
+ (someOtherCondition ? "Bar" : "") + "End";

... that becomes hard to read. And if there are more statements within the if bodies, it may not even be feasible.

To correct something within your question though:

As I understand it, when I do String baz = "foo" + "bar" + "123" the java compiler internally replaces the expression with a StringBuilder.

No, when you write that expression the compiler recognizes that it's a compile-time constant, and replaces it with

String baz = "foobar123";

That's a very good reason not to explicitly use a StringBuilder - the code above is clearly more efficient at execution time than

String baz = new StringBuilder("foo").append("bar").append("123").toString();

When it isn't a compile-time constant, the Java compiler will perform the concatenation using a StringBuilder, usually leaving you with easier-to-understand code than with the explicit use of StringBuilder, but with no performance hit. I suspect your teacher either doesn't properly understand string concatenation, or simply read somewhere else that you should use StringBuilder without fully understanding when it's appropriate.

In Java, when should I prefer String over StringBuilder vice versa?

You should use String, because String objects are cached in an object pool and might deliver better performance when you don't change them.

A StringBuilder is only useful when you keep on concatenating String tokens, which shouldn't be the case in a well normalized database table.

The JVM does all sorts of optimizations and chances are that even if you use concatenation the JVM might rewrite that routine to a StringBuilder version.

How to use StringBuilder wisely?

Modifying immutable structures like strings must be done by copying the structure, and by that, consuming more memory and slowing the application's run time (also increasing GC time, etc...).

StringBuilder comes to solve this problem by using the same mutable object for manipulations.

However:

when concatenating a string in compile time as the following:

string myString = "123";
myString += "234";
myString += "345";

it will actually compile to something like that:

string myString = string.Concat("123", "234", "345");

this function is faster than working with StringBuilder for the number of strings entering the function is known.

so for compile-time-known string concatenations you should prefer string.Concat().

as for unknown number of string like in the following case:

string myString = "123";
if (Console.ReadLine() == "a")
{
myString += "234";
}
myString += "345";

Now the compiler can't use the string.Concat() function, however, StringBuilder appears to be more efficient in time and memory consumption only when the concatenation is done with 6-7 or more strings.

Bad practice usage:

StringBuilder myString = new StringBuilder("123");
myString.Append("234");
myString.Append("345");

Fine practice usage (note that if is used):

StringBuilder myString = new StringBuilder("123");
if (Console.ReadLine() == "a")
{
myString.Append("234");
}
myString.Append("345");

Best practice usage (note that while loop is used):

StringBuilder myString = new StringBuilder("123");
while (Console.ReadLine() == "a")
{
myString.Append("234"); //Average loop times 4~ or more
}
myString.Append("345");

StringBuilder vs String concatenation in toString() in Java

Version 1 is preferable because it is shorter and the compiler will in fact turn it into version 2 - no performance difference whatsoever.

More importantly given we have only 3
properties it might not make a
difference, but at what point do you
switch from concat to builder?

At the point where you're concatenating in a loop - that's usually when the compiler can't substitute StringBuilder by itself.

How to use stringBuilder

To prevent writing the same (partial) string literal multiple times, you can:

  • Use a constant for the common part:

    if (CollectionUtils.isEmpty(primaryPathList)) {
    final String COMMON = "Customer Hierarchy is mandatory field";
    if (salesChannelCode.equals(SalesChannelType.HEB_TO_YOU)) {
    return Optional.of(COMMON + " for HebToYou.");
    } else {
    return Optional.of(COMMON + ".");
    }
    }
  • Build the string using StringBuilder:

    if (CollectionUtils.isEmpty(primaryPathList)) {
    StringBuilder buf = new StringBuilder("Customer Hierarchy is mandatory field");
    if (salesChannelCode.equals(SalesChannelType.HEB_TO_YOU)) {
    buf.append(" for HebToYou");
    }
    return Optional.of(buf.append('.').toString());
    }

Personally, I would keep the code in the question, especially if you ever might need support non-English versions of the text, because in other languages the extra text might not go there.

when to use string over stringbuilder/stringbuffer?

A String offers more functionalities than a StringBuilder. The sole purpose of a StringBuilder, as its name implies, is to build a String.

A String is not less efficient than a StringBuilder (don't know where you got that). It is actually much more efficient, because since it's immutable, you can sefely share references without needing defensive copies.

And most importantly: performance is usually not the main concern anyway. What matters more is correctness, readability, safety, maintainability. And using an immutable String increases all these factors.

If String is so much better than a StringBuilder, then why do we have a StringBuilder? Because there is one use-case where using a StringBuilder is much more efficient than using a String: constructing a String by repeatedly appending parts:

String s = "";
for (String part: collection) {
s += part;
}

The above code is slow because many temporary String objects are created and copied, and must then be GCed. In that case, use a StringBuilder:

StringBuilder builder = new StringBuilder();
for (String part: collection) {
builder.append(part);
}
String s = builder.toString();

Why StringBuilder when there is String?

String does not allow appending. Each method you invoke on a String creates a new object and returns it. This is because String is immutable - it cannot change its internal state.

On the other hand StringBuilder is mutable. When you call append(..) it alters the internal char array, rather than creating a new string object.

Thus it is more efficient to have:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 500; i ++) {
sb.append(i);
}

rather than str += i, which would create 500 new string objects.

Note that in the example I use a loop. As helios notes in the comments, the compiler automatically translates expressions like String d = a + b + c to something like

String d = new StringBuilder(a).append(b).append(c).toString();

Note also that there is StringBuffer in addition to StringBuilder. The difference is that the former has synchronized methods. If you use it as a local variable, use StringBuilder. If it happens that it's possible for it to be accessed by multiple threads, use StringBuffer (that's rarer)



Related Topics



Leave a reply



Submit