views:

167

answers:

6

Hello

I read a lot about using StringBuffer and String especially where concatenation is concerned in Java and whether one is thread safe or not.

So, in various Java methods, which should be used?

For example, in a PreparedStatement, should query be a StringBuffer:

    String query = ("SELECT * " +
                    "FROM User " +
                    "WHERE userName = ?;");

    try {
        ps = connection.prepareStatement(query);

And then again, in a String utility methods like:

public static String prefixApostrophesWithBackslash(String stringIn) {
    String stringOut = stringIn.replaceAll("'", "\\\\'");
    return stringOut;
}

And:

 // Removes a char from a String.
public static String removeChar(String stringIn, char c) {
    String stringOut = ("");
    for (int i = 0; i < stringIn.length(); i++) {
        if (stringIn.charAt(i) != c) {
            stringOut += stringIn.charAt(i);
        }
    }
    return stringOut;
}

Should I be using StringBuffers? Especially where repalceAll is not available for such objects anyway.

Thanks

Mr Morgan.

Thanks for all the advice. StringBuffers have been replaced with StringBuilders and Strings replaced with StringBuilders where I've thought it best.

+5  A: 

You almost never need to use StringBuffer.

Instead of StringBuffer you probably mean StringBuilder. A StringBuffer is like a StringBuilder except that it also offers thread safety. This thread safety is rarely needed in practice and will just cause your code to run more slowly.

Your question doesn't seem to be about String vs StringBuffer, but about using built-in methods or implementing the code yourself. If there is a built-in method that does exactly what you want, you should probably use it. The chances are it is much better optimized than the code you would write.

Mark Byers
I would hope that in the first example no StringBuilder is used internally, instead the compiler can just concatenate the strings into one string, since there is no variability.
Thomas Lötzer
That's a very good point... removed that bit.
Mark Byers
But given that this PreparedStatement could be used in a multi-threaded scenario, wouldn't StringBuffer be better?
Mr Morgan
@Mr Morgan - you'd be using the StringBuilder as an intermediate step to build the query string, and this local variable would not be visible by other threads. So there'd be no concurrency concerns for it - don't simple assume that "multithreaded app => use threadsafe classes everywhere".
Andrzej Doyle
+1  A: 

For the below segment of code

 // Removes a char from a String.
public static String removeChar(String stringIn, char c) {
    String stringOut = ("");
    for (int i = 0; i < stringIn.length(); i++) {
        if (stringIn.charAt(i) != c) {
            stringOut += stringIn.charAt(i);
        }
    }
    return stringOut;
}

You could just do stringIn.replaceAll(c+"","")

Bragboy
A: 

For cases which can be considered single threaded, the best would be StringBuilder. It does not add any synchronization overhead, while StringBuffer does.

String concatenation by '+' operator is "good" only when you're lazy to use StringBuilder or just want to keep the code easily readable and it is acceptable from performance point of view, like in startup log message "LOG.info("Starting instance " + inst_id + " of " + app_name);"

bobah
Actually, in the vast majority of cases, the compiler will turn the second form into a sequence of StringBuilder calls. So typically, it's **better** to use the string concatenation for the kind of thing you gave in your example since it's cleaner. You'd use StringBuilder for anything you're not concatenating directly together; e.g. in a loop, or when you're passing the builder between function calls.
Andrzej Doyle
@Andrzej Doyle - Actually, I did suggest using string concatenation in my example. Please read carefully before commenting.
bobah
Yes, but your second paragraph implies that the performance is inferior. My point was that in most cases (where the concantenation operation is lexically static) the compiler will turn it into StringBuilder-equivalent bytecode *anyway*. So you get to have your cake and eat it, which is not the impression I felt that you gave.
Andrzej Doyle
+1  A: 

Even in MT code, it's unusual to have multiple threads append stuff to a string. StringBuilder is almost always preferred to StringBuffer.

seand
+3  A: 

There is no simple answer (apart from repeating the mantra of StringBuilder versus StringBuffer ... ). You really have understand a fair bit about what goes on "under the hood" in order to pick the most efficient solution.

In your first example, String is the way to go. The Java compiler can generate pretty much optimal code (using a StringBuilder if necessary) for any expression consisting of a sequence of String concatenations. And, if the strings that are concatenated are all constants or literals, the compiler can actually do the concatenation at compile time.

In your second example, it is not entirely clear whether String or StringBuilder would be better ... or whether they would be roughly equivalent. One would need to look at the code of the java.util.regex.Matcher class to figure this out.

EDIT - I looked at the code, and actually it makes little difference whether you use a String or StringBuilder as the source. Internally the Matcher.replaceAll method creates a new StringBuilder and fills it by appending chunks from the source String and the replacement String.

In your third example, a StringBuilder would clearly be best. A current generation Java compiler is not able to optimize the code (as written) to avoid creating a new String as each character is added.

Stephen C
+1  A: 

Modern compilers optimize the code already. So some String additions will be optimized to use StringBuilder and we can keep the String additions if we think, it increases readibility.

Example 1:

String query = ("SELECT * " +
                "FROM User " +
                "WHERE userName = ?;");

will be optimized to somthing like:

StringBuiler sb = new StringBuilder();
sb.append("SELECT * ");
sb.append("FROM User ");
sb.append("WHERE userName = ?;");
String query = sb.toString();

Example 2:

String numbers = "";
for (int i = 0;i < 20; i++)
  numbers = numbers + i;

This can't be optimized and we should use a StringBuilder in code.


I made this observation for SUN jdk1.5+. So for older Java versions or different jdks it can be different. There it could be save to always code StringBuilder (or StringBuffer for jdk 1.4.2 and older).

Andreas_D
Actually, when concatenating string constants, the compiler will optimize it into a single string constant.
ILMTitan