That building Strings using StringBuffer (and in Java 5 StringBuilder) is much faster and less memory expensive than using String concatenation, is not a secret.
But porting this concept to extremes, you can fall in coding conventions that mandate to never use String concatenation. And you can face hibernate queries like this:
1String alias = "cd"; 2 3StringBuffer expression = new StringBuffer("select "); 4expression.append(alias).append(".account.name, "); 5expression.append(alias).append(".startDate, "); 6expression.append("sum(").append(alias).append(".duration), "); 7expression.append("sum(").append(alias).append(".cost), "); 8expression.append(alias).append(".account.id from "); 9expression.append(Test.class.getName()).append(" as ").append(alias); 10expression.append(" order by ").append(alias).append(".startDate desc "); 11 12String result = expression.toString(); 13// hibernate.executeQuery(...result...);
Cool! Only real programmers can read it, isn’t that? ]:)
You can imagine, that I love to write code this way… Jokes apart, imagine the time wasted beeing caught executing wrong queries and debugging this!
I tried to discuss this rule, but no-way… being a contractor, I always have to surrender to major forces :-), and this costs me pains. But at least this time we’ve discussed (a little, and here’s my rant). So the code it’s there. Fortunately in Hibernate 3.x we use Criterion and Projection APIs, so wrinting this kind of code is nomore in my task list. Few!
But going back at that time, you may think that a code like this below is easier to read but slower to execute:
1String expression = 2 "select " + 3 "cd.account.name, " + 4 "cd.startDate, " + 5 "sum(cd.duration), " + 6 "sum(cd.cost), " + 7 "cd.account.id " + 8 "from " + 9 Test.class.getName() + 10 " as cd " + "order by " + 11 "cd.startDate desc"; 12String result = expression; 13// hibernate.executeQuery(...result...);
If you think that it’s slower, you are wrong! Compilers are there to optimize code. String concatenations is made using StringBuffers by the compiler. The compiler can also inline string constants in a single one. Here’s an example on how the compiler can arrange our previous code:
1String expression = (new StringBuffer("select cd.account.name, cd.startDate, sum(cd.duration), sum(cd.cost), cd.account.id from ")).append(Test.getName()).append(" as cd ").append("order by ").append("cd.startDate desc").toString();
I’ve made a little class to compare performance between StringBuffers and String Concatenations for methods building queries like this.
Here’s the code (results follow)
1public class Test { 2 public interface Repeatable { 3 void iteration(long loopId); 4 } 5 6 public static long repeat(int times, Repeatable repeatable) { 7 long initial = System.currentTimeMillis(); 8 for (long c = 1; c <= times; c++) 9 repeatable.iteration(c); 10 long elapsed = System.currentTimeMillis() - initial; 11 return elapsed; 12 } 13 14 private static Repeatable stringBufferTest = new Repeatable() { 15 public void iteration(long loopId) { 16 String alias = "cd"; 17 StringBuffer expression = new StringBuffer("select "); 18 expression.append(alias).append(".account.name, "); 19 expression.append(alias).append(".startDate, "); 20 expression.append("sum(").append(alias).append(".duration), "); 21 expression.append("sum(").append(alias).append(".cost), "); 22 expression.append(alias).append(".account.id from "); 23 expression.append(Test.class.getName()).append(" as ").append(alias); 24 expression.append(" order by ").append(alias).append(".startDate desc "); 25 String result = expression.toString(); 26 } 27 }; 28 29 private static Repeatable stringConcatenationTest = new Repeatable() { 30 public void iteration(long loopId) { 31 String expression = 32 "select " + 33 "cd.account.name, " + 34 "cd.startDate, " + 35 "sum(cd.duration), " + 36 "sum(cd.cost), " + 37 "cd.account.id " + 38 "from " + 39 Test.class.getName() + 40 " as cd " + "order by " + 41 "cd.startDate desc"; 42 String result = expression; 43 } 44 }; 45 46 public static void main(String[] args) { 47 for (int loopCount = 1; loopCount <= 5; loopCount++) { 48 int times = 1000000; 49 long stringBuffElapsed, stringConcatElapsed; 50 51 stringBuffElapsed = repeat(times, stringBufferTest); 52 stringConcatElapsed = repeat(times, stringConcatenationTest); 53 54 System.out.println("Results for iteration " + loopCount); 55 System.out.println("StringBuffer Build. " + stringBuffElapsed); 56 System.out.println("String Concatenat. " + stringConcatElapsed + "\n"); 57 } 58 } 59}
Here the output:
Results for iteration 1 StringBuffer Build. 3085 String Concatenat. 1492 Results for iteration 2 StringBuffer Build. 3044 String Concatenat. 1612 Results for iteration 3 StringBuffer Build. 3205 String Concatenat. 1793 Results for iteration 4 StringBuffer Build. 3745 String Concatenat. 1783 Results for iteration 5 StringBuffer Build. 3505 String Concatenat. 2353
For this case, String concatenations is twice faster than StringBuffer!
Conclusions: don’t use String concatenations to build big strings (expecially inside loops), use StringBuffers everytime possible, but leave your source code readable! And… never forget Rules of Optimization. Personally, I prefere code (a little) slower but more readable. And, when possible, faster and more readable, like in this case.
One Response to “StringBuffer considered harmuful”
Leave a Reply
Search
Follow me
Archives
Categories
- Android (3)
- Apple (29)
- Books (7)
- Eclipse (14)
- Errors (5)
- Firefox (7)
- Git (3)
- Hardware (18)
- Horror Code (8)
- Internet (21)
- Java (104)
- JavaScript (9)
- Life, universe and everything (45)
- Lifehacks (26)
- Linux (52)
- Opinions (26)
- OSX (11)
- OWNER API (2)
- Python (1)
- Software (33)
- Speeches and Conferences (8)
- Unix (5)
- Web (23)
- Windows (19)
Tag Cloud
Android apple architecture Bash configuration CSS Development Düsseldorf Eclipse Git Google Hardware hdr How-To howto Java JAXB job Karmic Linux lion MacBook music Open Source Opinion OSX os x patterns Pitfalls Practices Resume Security Software Suspend TDD Testing tip tonemapped Tricks Ubuntu unix video Web Workaround XML
WP Cumulus Flash tag cloud by Roy Tanck and Luke Morton requires Flash Player 9 or better.
Blog License
Blogs I like
Books on the desk
Friends' Blogs
- Antonio Terreno & Valter Bernardini
- Bruno Bossola
- Daniele Galluccio
- Domenico Ventura
- Ed Schepis
- Fabrizio Gianneschi
- Luca Grulla
- Luigi Zanderighi
- Marcello Teodori
- Mida Boghetich
- Muralidharan Chandrasekaran
- Piero Ricca
- Renzo Borgatti
- Simone Bordet
- Simone Bruno
- Uberto Barbini
- Valvolog
- Webtide blogs (Greg Wilkins & Jan Bartel)
Links


















Hi,
I understand what you are trying to say. BUT i can’t agree on some points and a liite bit confused of how/ why are you demonstrating such stuff … so prob., the questions I would ask here:
Why are you creating a new StringBuffer each time?
Without running this test, I can assume taht will be slow down the process, if you re-locate thet one in front of loop OR insert a real new String() on each place where you work with strings, that might be closer to a real compare.
Even if they are internal compiler, whci is right an very important, we might provide at least similar stuff; for instance:
String expression = new String();
expression = “bla”;
expression = “bla ba”;
OR choose the same logic on StringBuffe side:
String expression = new StringBuffer( “bla”.length*3 );
expression.append(“bla”).append(bla”).append(bla”);
Well … however, I won’t use Strings anyway if I can avoid it ;)
If you think that’s better, of course that will be fine.
Cheers!