Correct way to use StringBuilder in SQL - java

I just found some sql query build like this in my project:
return (new StringBuilder("select id1, " + " id2 " + " from " + " table")).toString();
Does this StringBuilder achieve its aim, i.e reducing memory usage?
I doubt that, because in the constructor the '+' (String concat operator) is used. Will that take the same amount of memory as using String like the code below? s I understood, it differs when using StringBuilder.append().
return "select id1, " + " id2 " + " from " + " table";
Are both statements equal in memory usage or not? Please clarify.
Edit:
BTW, it is not my code. Found it in an old project. Also, the query is not so small as the one in my example. :)

The aim of using StringBuilder, i.e reducing memory. Is it achieved?
No, not at all. That code is not using StringBuilder correctly. (I think you've misquoted it, though; surely there aren't quotes around id2 and table?)
Note that the aim (usually) is to reduce memory churn rather than total memory used, to make life a bit easier on the garbage collector.
Will that take memory equal to using String like below?
No, it'll cause more memory churn than just the straight concat you quoted. (Until/unless the JVM optimizer sees that the explicit StringBuilder in the code is unnecessary and optimizes it out, if it can.)
If the author of that code wants to use StringBuilder (there are arguments for, but also against; see note at the end of this answer), better to do it properly (here I'm assuming there aren't actually quotes around id2 and table):
StringBuilder sb = new StringBuilder(some_appropriate_size);
sb.append("select id1, ");
sb.append(id2);
sb.append(" from ");
sb.append(table);
return sb.toString();
Note that I've listed some_appropriate_size in the StringBuilder constructor, so that it starts out with enough capacity for the full content we're going to append. The default size used if you don't specify one is 16 characters, which is usually too small and results in the StringBuilder having to do reallocations to make itself bigger (IIRC, in the Sun/Oracle JDK, it doubles itself [or more, if it knows it needs more to satisfy a specific append] each time it runs out of room).
You may have heard that string concatenation will use a StringBuilder under the covers if compiled with the Sun/Oracle compiler. This is true, it will use one StringBuilder for the overall expression. But it will use the default constructor, which means in the majority of cases, it will have to do a reallocation. It's easier to read, though. Note that this is not true of a series of concatenations. So for instance, this uses one StringBuilder:
return "prefix " + variable1 + " middle " + variable2 + " end";
It roughly translates to:
StringBuilder tmp = new StringBuilder(); // Using default 16 character size
tmp.append("prefix ");
tmp.append(variable1);
tmp.append(" middle ");
tmp.append(variable2);
tmp.append(" end");
return tmp.toString();
So that's okay, although the default constructor and subsequent reallocation(s) isn't ideal, the odds are it's good enough — and the concatenation is a lot more readable.
But that's only for a single expression. Multiple StringBuilders are used for this:
String s;
s = "prefix ";
s += variable1;
s += " middle ";
s += variable2;
s += " end";
return s;
That ends up becoming something like this:
String s;
StringBuilder tmp;
s = "prefix ";
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable1);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" middle ");
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable2);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" end");
s = tmp.toString();
return s;
...which is pretty ugly.
It's important to remember, though, that in all but a very few cases it doesn't matter and going with readability (which enhances maintainability) is preferred barring a specific performance issue.

When you already have all the "pieces" you wish to append, there is no point in using StringBuilder at all. Using StringBuilder and string concatenation in the same call as per your sample code is even worse.
This would be better:
return "select id1, " + " id2 " + " from " + " table";
In this case, the string concatenation is actually happening at compile-time anyway, so it's equivalent to the even-simpler:
return "select id1, id2 from table";
Using new StringBuilder().append("select id1, ").append(" id2 ")....toString() will actually hinder performance in this case, because it forces the concatenation to be performed at execution time, instead of at compile time. Oops.
If the real code is building a SQL query by including values in the query, then that's another separate issue, which is that you should be using parameterized queries, specifying the values in the parameters rather than in the SQL.
I have an article on String / StringBuffer which I wrote a while ago - before StringBuilder came along. The principles apply to StringBuilder in the same way though.

[[ There are some good answers here but I find that they still are lacking a bit of information. ]]
return (new StringBuilder("select id1, " + " id2 " + " from " + " table"))
.toString();
So as you point out, the example you give is a simplistic but let's analyze it anyway. What happens here is the compiler actually does the + work here because "select id1, " + " id2 " + " from " + " table" are all constants. So this turns into:
return new StringBuilder("select id1, id2 from table").toString();
In this case, obviously, there is no point in using StringBuilder. You might as well do:
// the compiler combines these constant strings
return "select id1, " + " id2 " + " from " + " table";
However, even if you were appending any fields or other non-constants then the compiler would use an internal StringBuilder -- there's no need for you to define one:
// an internal StringBuilder is used here
return "select id1, " + fieldName + " from " + tableName;
Under the covers, this turns into code that is approximately equivalent to:
StringBuilder sb = new StringBuilder("select id1, ");
sb.append(fieldName).append(" from ").append(tableName);
return sb.toString();
Really the only time you need to use StringBuilder directly is when you have conditional code. For example, code that looks like the following is desperate for a StringBuilder:
// 1 StringBuilder used in this line
String query = "select id1, " + fieldName + " from " + tableName;
if (where != null) {
// another StringBuilder used here
query += ' ' + where;
}
The + in the first line uses one StringBuilder instance. Then the += uses another StringBuilder instance. It is more efficient to do:
// choose a good starting size to lower chances of reallocation
StringBuilder sb = new StringBuilder(64);
sb.append("select id1, ").append(fieldName).append(" from ").append(tableName);
// conditional code
if (where != null) {
sb.append(' ').append(where);
}
return sb.toString();
Another time that I use a StringBuilder is when I'm building a string from a number of method calls. Then I can create methods that take a StringBuilder argument:
private void addWhere(StringBuilder sb) {
if (where != null) {
sb.append(' ').append(where);
}
}
When you are using a StringBuilder, you should watch for any usage of + at the same time:
sb.append("select " + fieldName);
That + will cause another internal StringBuilder to be created. This should of course be:
sb.append("select ").append(fieldName);
Lastly, as #T.J.rowder points out, you should always make a guess at the size of the StringBuilder. This will save on the number of char[] objects created when growing the size of the internal buffer.

You are correct in guessing that the aim of using string builder is not achieved, at least not to its full extent.
However, when the compiler sees the expression "select id1, " + " id2 " + " from " + " table" it emits code which actually creates a StringBuilder behind the scenes and appends to it, so the end result is not that bad afterall.
But of course anyone looking at that code is bound to think that it is kind of retarded.

In the code you have posted there would be no advantages, as you are misusing the StringBuilder. You build the same String in both cases. Using StringBuilder you can avoid the + operation on Strings using the append method.
You should use it this way:
return new StringBuilder("select id1, ").append(" id2 ").append(" from ").append(" table").toString();
In Java, the String type is an inmutable sequence of characters, so when you add two Strings the VM creates a new String value with both operands concatenated.
StringBuilder provides a mutable sequence of characters, which you can use to concat different values or variables without creating new String objects, and so it can sometimes be more efficient than working with strings
This provides some useful features, as changing the content of a char sequence passed as parameter inside another method, which you can't do with Strings.
private void addWhereClause(StringBuilder sql, String column, String value) {
//WARNING: only as an example, never append directly a value to a SQL String, or you'll be exposed to SQL Injection
sql.append(" where ").append(column).append(" = ").append(value);
}
More info at http://docs.oracle.com/javase/tutorial/java/data/buffers.html

You could also use MessageFormat too

Related

Stringbuilder for Constants

In application, we are using lot of SQL queries which we are assigning it in a String constants. So my question is by replacing String with StringBuilder ,whether it can improve the performance as we have to do lot of concatenations for large SQL queries. That is in the below two approaches, which is the best approach:
Approach 1:
String sql= "select * from table1" + " table2 where column = :1";
Approach 2:
StringBuilder sql = new StringBuilder("select * from table1").
append( "table2 where column = :1" );
Can anyone suggest
Use string concatenation (with the + operator).
If the expressions are compile-time constant expressions then they will be evaluated at compile time.
If they are not; e.g.
String sql = "select * from " + tableName() + " where column = :1";
it is still better to let the compiler(s) optimize the concatenation, whether the expression is (runtime) constant or not. They should turn the above into equivalent code using StringBuilder.
The only scenario where you should consider using StringBuilder explicitly is when you are doing things like this:
String sql= "select * from table where ";
for (String part: parts) {
sql += part + " ";
}
Current generation compilers cannot optimize the above.
Finally, do not use StringBuilder to represent constants. They are mutable ... not constant.
Author note: the above examples are for illustration only. Think SQL injection! Use PreparedStatement.
If you really want to use stringbuilder, you can of course to make anywhere- some common utils class / DB utils usually, method like following.
but I dont think it will have better performance (or maybe yes, I guess it will dont be something extra improvement) for this case. From my point of view is looks #Stephen C example better
public static String composeSQLQuery(String columns,String tableName,String restrictions) {
StringBuilder sb = new StringBuilder("Select");
sb.append(" ");
sb.append(columns);
sb.append(" ");
sb.append("from");
sb.append(" ");
sb.append(tableName);
sb.append(" ");
sb.append("where");
sb.append(" ");
sb.append(restrictions);
return sb.toString();
}
In your case, it's no need to use Stringbuilder, because from the jdk5, the compiler automatically convert concentration to stringbuilder.
For example:
String a = "abc" + "def" + "xyz";
is equivalent with:
Stringbuilder a = new Stringbuilder();
a.append("abc");
a.append("def");
a.append("xyz");
But in case the concentration is in the loop, like:
String a = "";
for (int i = 0; i<10; i++){
a += "str";
}
Then, you should need to use Stringbuilder instead, because in this case, java cannot optimize the code and convert the concentration to Stringbuilder automatically.

Using only 1 System.out.print() instead of 3. More details below [duplicate]

I am trying to concatenate strings in Java. Why isn't this working?
public class StackOverflowTest {
public static void main(String args[]) {
int theNumber = 42;
System.out.println("Your number is " . theNumber . "!");
}
}
You can concatenate Strings using the + operator:
System.out.println("Your number is " + theNumber + "!");
theNumber is implicitly converted to the String "42".
The concatenation operator in java is +, not .
Read this (including all subsections) before you start. Try to stop thinking the php way ;)
To broaden your view on using strings in Java - the + operator for strings is actually transformed (by the compiler) into something similar to:
new StringBuilder().append("firstString").append("secondString").toString()
There are two basic answers to this question:
[simple] Use the + operator (string concatenation). "your number is" + theNumber + "!" (as noted elsewhere)
[less simple]: Use StringBuilder (or StringBuffer).
StringBuilder value;
value.append("your number is");
value.append(theNumber);
value.append("!");
value.toString();
I recommend against stacking operations like this:
new StringBuilder().append("I").append("like to write").append("confusing code");
Edit: starting in java 5 the string concatenation operator is translated into StringBuilder calls by the compiler. Because of this, both methods above are equal.
Note: Spaceisavaluablecommodity,asthissentancedemonstrates.
Caveat: Example 1 below generates multiple StringBuilder instances and is less efficient than example 2 below
Example 1
String Blam = one + two;
Blam += three + four;
Blam += five + six;
Example 2
String Blam = one + two + three + four + five + six;
Out of the box you have 3 ways to inject the value of a variable into a String as you try to achieve:
1. The simplest way
You can simply use the operator + between a String and any object or primitive type, it will automatically concatenate the String and
In case of an object, the value of String.valueOf(obj) corresponding to the String "null" if obj is null otherwise the value of obj.toString().
In case of a primitive type, the equivalent of String.valueOf(<primitive-type>).
Example with a non null object:
Integer theNumber = 42;
System.out.println("Your number is " + theNumber + "!");
Output:
Your number is 42!
Example with a null object:
Integer theNumber = null;
System.out.println("Your number is " + theNumber + "!");
Output:
Your number is null!
Example with a primitive type:
int theNumber = 42;
System.out.println("Your number is " + theNumber + "!");
Output:
Your number is 42!
2. The explicit way and potentially the most efficient one
You can use StringBuilder (or StringBuffer the thread-safe outdated counterpart) to build your String using the append methods.
Example:
int theNumber = 42;
StringBuilder buffer = new StringBuilder()
.append("Your number is ").append(theNumber).append('!');
System.out.println(buffer.toString()); // or simply System.out.println(buffer)
Output:
Your number is 42!
Behind the scene, this is actually how recent java compilers convert all the String concatenations done with the operator +, the only difference with the previous way is that you have the full control.
Indeed, the compilers will use the default constructor so the default capacity (16) as they have no idea what would be the final length of the String to build, which means that if the final length is greater than 16, the capacity will be necessarily extended which has price in term of performances.
So if you know in advance that the size of your final String will be greater than 16, it will be much more efficient to use this approach to provide a better initial capacity. For instance, in our example we create a String whose length is greater than 16, so for better performances it should be rewritten as next:
Example optimized :
int theNumber = 42;
StringBuilder buffer = new StringBuilder(18)
.append("Your number is ").append(theNumber).append('!');
System.out.println(buffer)
Output:
Your number is 42!
3. The most readable way
You can use the methods String.format(locale, format, args) or String.format(format, args) that both rely on a Formatter to build your String. This allows you to specify the format of your final String by using place holders that will be replaced by the value of the arguments.
Example:
int theNumber = 42;
System.out.println(String.format("Your number is %d!", theNumber));
// Or if we need to print only we can use printf
System.out.printf("Your number is still %d with printf!%n", theNumber);
Output:
Your number is 42!
Your number is still 42 with printf!
The most interesting aspect with this approach is the fact that we have a clear idea of what will be the final String because it is much more easy to read so it is much more easy to maintain.
The java 8 way:
StringJoiner sj1 = new StringJoiner(", ");
String joined = sj1.add("one").add("two").toString();
// one, two
System.out.println(joined);
StringJoiner sj2 = new StringJoiner(", ","{", "}");
String joined2 = sj2.add("Jake").add("John").add("Carl").toString();
// {Jake, John, Carl}
System.out.println(joined2);
You must be a PHP programmer.
Use a + sign.
System.out.println("Your number is " + theNumber + "!");
"+" instead of "."
Use + for string concatenation.
"Your number is " + theNumber + "!"
This should work
public class StackOverflowTest
{
public static void main(String args[])
{
int theNumber = 42;
System.out.println("Your number is " + theNumber + "!");
}
}
For exact concatenation operation of two string please use:
file_names = file_names.concat(file_names1);
In your case use + instead of .
For better performance use str1.concat(str2) where str1 and str2 are string variables.
String.join( delimiter , stringA , stringB , … )
As of Java 8 and later, we can use String.join.
Caveat: You must pass all String or CharSequence objects. So your int variable 42 does not work directly. One alternative is using an object rather than primitive, and then calling toString.
Integer theNumber = 42;
String output =
String // `String` class in Java 8 and later gained the new `join` method.
.join( // Static method on the `String` class.
"" , // Delimiter.
"Your number is " , theNumber.toString() , "!" ) ; // A series of `String` or `CharSequence` objects that you want to join.
) // Returns a `String` object of all the objects joined together separated by the delimiter.
;
Dump to console.
System.out.println( output ) ;
See this code run live at IdeOne.com.
In java concatenate symbol is "+".
If you are trying to concatenate two or three strings while using jdbc then use this:
String u = t1.getString();
String v = t2.getString();
String w = t3.getString();
String X = u + "" + v + "" + w;
st.setString(1, X);
Here "" is used for space only.
In Java, the concatenation symbol is "+", not ".".
"+" not "."
But be careful with String concatenation. Here's a link introducing some thoughts from IBM DeveloperWorks.
You can concatenate Strings using the + operator:
String a="hello ";
String b="world.";
System.out.println(a+b);
Output:
hello world.
That's it
So from the able answer's you might have got the answer for why your snippet is not working. Now I'll add my suggestions on how to do it effectively. This article is a good place where the author speaks about different way to concatenate the string and also given the time comparison results between various results.
Different ways by which Strings could be concatenated in Java
By using + operator (20 + "")
By using concat method in String class
Using StringBuffer
By using StringBuilder
Method 1:
This is a non-recommended way of doing. Why? When you use it with integers and characters you should be explicitly very conscious of transforming the integer to toString() before appending the string or else it would treat the characters to ASCI int's and would perform addition on the top.
String temp = "" + 200 + 'B';
//This is translated internally into,
new StringBuilder().append( "" ).append( 200 ).append('B').toString();
Method 2:
This is the inner concat method's implementation
public String concat(String str) {
int olen = str.length();
if (olen == 0) {
return this;
}
if (coder() == str.coder()) {
byte[] val = this.value;
byte[] oval = str.value;
int len = val.length + oval.length;
byte[] buf = Arrays.copyOf(val, len);
System.arraycopy(oval, 0, buf, val.length, oval.length);
return new String(buf, coder);
}
int len = length();
byte[] buf = StringUTF16.newBytesFor(len + olen);
getBytes(buf, 0, UTF16);
str.getBytes(buf, len, UTF16);
return new String(buf, UTF16);
}
This creates a new buffer each time and copies the old content to the newly allocated buffer. So, this is would be too slow when you do it on more Strings.
Method 3:
This is thread safe and comparatively fast compared to (1) and (2). This uses StringBuilder internally and when it allocates new memory for the buffer (say it's current size is 10) it would increment it's 2*size + 2 (which is 22). So when the array becomes bigger and bigger this would really perform better as it need not allocate buffer size each and every time for every append call.
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
int newCapacity = (oldCapacity << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
private int hugeCapacity(int minCapacity) {
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
int UNSAFE_BOUND = Integer.MAX_VALUE >> coder;
if (UNSAFE_BOUND - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > SAFE_BOUND)
? minCapacity : SAFE_BOUND;
}
Method 4
StringBuilder would be the fastest one for String concatenation since it's not thread safe. Unless you are very sure that your class which uses this is single ton I would highly recommend not to use this one.
In short, use StringBuffer until you are not sure that your code could be used by multiple threads. If you are damn sure, that your class is singleton then go ahead with StringBuilder for concatenation.
First method: You could use "+" sign for concatenating strings, but this always happens in print.
Another way: The String class includes a method for concatenating two strings: string1.concat(string2);
import com.google.common.base.Joiner;
String delimiter = "";
Joiner.on(delimiter).join(Lists.newArrayList("Your number is ", 47, "!"));
This may be overkill to answer the op's question, but it is good to know about for more complex join operations. This stackoverflow question ranks highly in general google searches in this area, so good to know.
you can use stringbuffer, stringbuilder, and as everyone before me mentioned, "+". I'm not sure how fast "+" is (I think it is the fastest for shorter strings), but for longer I think builder and buffer are about equal (builder is slightly faster because it's not synchronized).
here is an example to read and concatenate 2 string without using 3rd variable:
public class Demo {
public static void main(String args[]) throws Exception {
InputStreamReader r=new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(r);
System.out.println("enter your first string");
String str1 = br.readLine();
System.out.println("enter your second string");
String str2 = br.readLine();
System.out.println("concatenated string is:" + str1 + str2);
}
}
There are multiple ways to do so, but Oracle and IBM say that using +, is a bad practice, because essentially every time you concatenate String, you end up creating additional objects in memory. It will utilize extra space in JVM, and your program may be out of space, or slow down.
Using StringBuilder or StringBuffer is best way to go with it. Please look at Nicolas Fillato's comment above for example related to StringBuffer.
String first = "I eat"; String second = "all the rats.";
System.out.println(first+second);
Using "+" symbol u can concatenate strings.
String a="I";
String b="Love.";
String c="Java.";
System.out.println(a+b+c);

Concatenation of constant strings VS StringBuffer

What arguments can You give for the use one or another variant that is better, faster, more correct.
First variant:
StringBuffer sql = new StringBuffer("SELECT DISTINCT f.ID ")
.append("FROM FIRST_TABLE F ")
.append("LEFT JOIN SECOND_TABLE s ON f.ID = s.F_ID ")
.append("WHERE ")
.append("F.BOOL = 1 ")
.append("AND S.DATE IS NOT NULL ")
.append("AND S.CLOSED = 0 ");
Second variant:
String sql = "SELECT DISTINCT f.ID " +
"FROM FIRST_TABLE F " +
"LEFT JOIN SECOND_TABLE s ON f.ID = s.F_ID " +
"WHERE "
"F.BOOL = 1 " +
"AND S.DATE IS NOT NULL " +
"AND S.CLOSED = 0";
*for note: Class String and Class StringBuffer.
The second is better:
It's clearer (more of the code has to do with what you want)
It's more efficient, as all the concatenation is being done at compile-time
Even if execution-time concatenation was required (e.g. you had a variable in there), the compiled code would use a StringBuilder or StringBuffer where it needed to (depending on the version of Java you're targeting).
Mind you, if you're executing a database query, the efficiency is going to be utterly insignificant.
You should not be wasting your time worrying about how to concatenate a few strings. Use 2 and keep it clear. Using StringBuilder/buffer is not the mark of a great programmer, if that's what you thought.
Worry about the vaguely defined requirements and the things behind schedule.
Try this ->
long finalTime1 = 0; {
long initialTimeTest = System.currentTimeMillis();
for( int index = 0; index < 10000; index++ ){ StringBuilder sb = new StringBuilder("Hello, ").append("World"); System.out.println(sb.toString()); }
finalTime1 = System.currentTimeMillis() - initialTimeTest;
}
long finalTime2 = 0; {
long initialTimeTest = System.currentTimeMillis();
for( int index = 0; index < 10000; index++ ){ String sb = "Hello, " + "World"; System.out.println( sb ); }
finalTime2 = System.currentTimeMillis() - initialTimeTest;
}
System.out.println( finalTime1 ); System.out.println( finalTime2 );
Results:
... Hello, World Hello, World 245 148
Did you think string buffer was faster ??
You are breaking the mother of all rules: Keep it Simple. -
For mundane string handling there is no reason why to use StringBuilder. It just adds unnecessary complexity to a mundane task.
We need to think BIG, think in the overall business impact of the module to the project. Discussing whether we shall assemble a few strings with StringBuilder/Builder or String is thinking little, - don't do that.
To your question about performance, I recommend:http://cfd.gmu.edu/~jcebral/academics/csi702/notes/02-optimization.pdf

Something crazy happens with StringBuilder.append(String str);

I've got a problem with my java-project.
following function should deliver a String for a SQL-Statement:
private static String createInsertString(Pat p)
{
StringBuilder x = new StringBuilder();
x.append("" + p.getPatnr() +","+ p.getSvnr());
java.sql.Date andat = null,gebdat;
if(p.getAndat()==null)
andat=null;
else
andat=new java.sql.Date(p.getAndat().getTimeInMillis());
if(p.getGebdat()==null)
gebdat=null;
else
gebdat=new java.sql.Date(p.getGebdat().getTimeInMillis());
x.append("," + andat==null?"null":andat);
x.append("," + p.getTele()==null?"null":p.getTele());
x.append("," + p.getVName() +","+ p.getNname());
x.append("," + p.getKk()==null?"null":p.getKk());
x.append("," + gebdat==null?"null":gebdat);
x.append("," + p.getAdrplzort()==null?"null":6);
x.append("," + p.getAdrstr()==null?"null":p.getAdrstr());
x.append("," + p.getAdrhnr()==null?"null":p.getAdrhnr());
s.append("," + p.getReplzort()==null?"null":p.getReplzort().getPlzortnr());
x.append("," + p.getRestr()==null?"null":p.getRestr());
x.append("," + p.getRehnr()==null?"null":p.getRehnr());
x.append("," + p.getLevel());
x.append("," + p.getCon()==null?"null":p.getCon());
x.append("," + (p.isPa()?"y":"n")+","+ (p.isLonly()?"y":"n") +","+ (p.isGest()?"y":"n"));
x.append("," + p.getBem()==null?"null":p.getBem());
x.append("," + (p.isKat1()?'y':'n') +","+ (p.isKat2()?'y':'n') +","+ (p.isKat3()?'y':'n'));
System.out.println(x);
return x.toString();
}
the output is
6,6465136nullnull,Jürgen,Wieslernullnull6nullnullnullnull,0null,n,n,nnull,n,n,n
but it should be like this:
6,6465136,null,null,Jürgen,Wiesler,null,null,6,null,null,null,null,0,null,n,n,n,null,n,n,n
Anyone an Idea?
I'm using jdk 1.7 on debian(64-bit)
The problem is how the operators bind. Look at this:
x.append("," + andat==null?"null":andat);
Now think of it as:
x.append(("," + andat) == null ? "null" : andat);
The LHS is never going to be null, so it's always just appending andat... and that still converts to "null" if the reference is null, because that's the default behaviour of StringBuilder.
Your code is much more complicated - and inefficient - than it needs to be. Consider rewriting it as:
private static String createInsertString(Pat p)
{
StringBuilder x = new StringBuilder();
java.sql.Date andat = p.andat == null ? null
: new java.sql.Date(p.getAndat().getTimeInMillis());
java.sql.Date gebdat = p.getGebdat() == null ? null
: new java.sql.Date(p.getGebdat().getTimeInMillis());
x.append(p.getPatnr()).append(",")
.append(p.getSvnr()).append(",")
.append(andat).append(",")
.append(p.getTele()).append(",")
// etc
return x.toString();
}
Note that I think you had a bug in the original:
x.append("," + p.getVName() +","+ p.getNname());
Where these meant to be calling two different getters?
You are misusing .append() by putting concatenations inside them! This misses the entire point of what StringBuilder is supposed to be used for.
x.append("," + andat==null?"null":andat);
should be
x.append(",").append( andat == null ? "null" : andat);
which would be the correct logic to make your ternary operator work as you intended.
.append() returns a reference to the StringBuilder so that you can chain .append() calls as much as you need.
Anytime you are putting a string concatenation inside of .append() you are just creating more intermediate String objects that eat up memory, cpu cycles and then use more resources as they now need to be garbage collected.
Also you should pre-allocate your StringBuilder with a default size that is slightly bigger than what you expect your contents to be to avoid wasted allocations and garbage creation.
See the Javadoc for the StringBuilder(int) constructor.
The problem comes from your '+'.
If you use a StringBuilder, don't use '+': it is not efficient
"," + andat==null?"null":andat results in ",null"==null?"null":andat if andat is null.
The '+' string concatenation has priority over the ternary operator
When you use the '+' with String your compiler actually translates that to a StringBuilder (or a StringBuffer before Java5)
So having
String s = a + b + c;
is actually translated to:
String s = new StringBuilder().append(a).append(b).append(c).toString().
Therefore using + within a StringBuilder is counter-productive as you create additional unecessary StringBuilder.

Trouble determining most efficient string concatenation

I use toString() method. But I don't know which implemention is better to use and why:
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Description: " + description + ";");
buffer.append("Price: " + price);
return buffer.toString();
}
public String toString() {
return "Description: " + description + ";" + "Price: " + price;
}
Personally I'd use the latter - it's clearer and is actually more efficient:
For modern versions of Java it'll use the unsynchronized StringBuilder type instead of StringBuffer
It won't construct the intermediate strings for "Price: " + price and "Description: " + description + ";" which are unnecessary,
Under Java 5+ I'd expect the latter code to be compiled to:
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Description: ");
builder.append(description);
builder.append(";");
builder.append("Price");
builder.append(price);
return builder.toString();
}
The important point is the clarity of the second form, however - I certainly find it much simpler to read than the first. One interesting point is that there are two consecutive calls to append with string constants in the compiled version (I've checked). It would be slightly more efficient - and even more readable, IMO - to write:
public String toString() {
return "Description: " + description + ";Price: " + price;
}
Both are exactly the same*, concatenation with the '+' operator effectively expands into the StringBuffer construct you gave as the first example.
EDIT: Actually it is a StringBuilder rather than a StringBuffer as of Java 5. The only difference is that the latter one is thread-safe and can be accessed by multiple threads without additional locking. Nevertheless it has an synchronization overhead you should avoid by using a StringBuilder whenever you are sure the object is not shared among different threads.
(*) Well, not exactly, if you nest additional concatenations in the append method, unnecessary temporary strings may be created, just as Jon Skeet pointed out. Did not notice that in your code. My bad.
It's just a personal preference, since it's both compiled the same according to the documentation:
String buffers are used by the compiler to implement the binary string
concatenation operator +. For example, the code:
x = "a" + 4 + "c" is compiled to the equivalent of:
x = new StringBuffer().append("a").append(4).append("c")
.toString()
also, i'd put #Override above your method.
In general it' better to use StringBuffer or StringBuilder. The different between StringBuffer and StringBuilder is that StringBuffer is synchronized. In your example I would recommend StringBuilder.
StringBuilder will allocate less frequently and this can provide significant speed and memory management improvements when you are doing this action a lot.
Please read there is much more on this topic here:
Why to use StringBuffer in Java instead of the string concatenation operator

Categories