Skip to content
Browse files

Fixed spurious post on strinbguilder, content now available

  • Loading branch information...
1 parent 25999cc commit f28aa6018f292f3dc550e34cff8f7213372dd44e @skuro committed
View
4 2013/03/06/java-stringbuilder-myth/index.html
@@ -74,9 +74,9 @@ <h5 class="date">
</blockquote>
- <img src="/img/post/jirasvn.png" class="primary" />
-
+ <img src="/img/post/joint.png" class="primary" />
+ <p><em>NOTE: this post was published before it was ready, the real content can now be found <a href="2013/03/11/java-stringbuilder-myth-now-with-content/">here</a></em></p>
<div id="disqus_thread"></div>
View
282 2013/03/11/java-stringbuilder-myth-now-with-content/index.html
@@ -0,0 +1,282 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+ <head>
+ <title>SKURO! -- Shading lights</title>
+ <meta name="generator" content="skuro.tk/0.1 | jekyll/0.11.0" />
+ <meta charset="utf-8" />
+ <meta name="description" content="Personal Blog of Carlo Sciolla" />
+ <meta name="keywords" content="clojure,enlive,moustache,java,alfresco,lambdalf,performance" />
+ <link rel="stylesheet" href="/stylesheets/styles.css" />
+ <link rel="stylesheet" href="/stylesheets/pygment_trac.css" />
+ <link rel="stylesheet" href="/stylesheets/skuro.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
+
+ <!--[if lt IE 9]>
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+ </head>
+ <body>
+ <div class="adsense">
+ <script type="text/javascript"><!--
+ google_ad_client = "ca-pub-5536661153340295";
+ /* ghpages-skyscraper */
+ google_ad_slot = "1277668326";
+ google_ad_width = 120;
+ google_ad_height = 600;
+ //-->
+ </script>
+ <script type="text/javascript"
+ src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+ </script>
+ </div>
+ <div class="wrapper">
+ <header>
+ <span class="avatar">
+ <img src="http://www.gravatar.com/avatar/3246c43cf35485e40a18e72fa1fa7ace" />
+ </span>
+ <h1><a href="/">SKURO!</a></h1>
+ <ul>
+ <li><a href="/archive">Browse the <strong>Archive</strong></a></li>
+ <li><a href="/category">Browse by <strong>Categories</strong></a></li>
+ <li><a href="/about">Learn more <strong>About me</strong></a></li>
+ </ul>
+ <p class="persona">
+ <a href="https://github.com/skuro"><img src="/img/github.png" /></a>
+ <a href="http://nl.linkedin.com/in/carlosciolla"><img src="/img/linkedin.png" /></a>
+ <a href="https://twitter.com/skuro"><img src="/img/twitter.png" /></a>
+ <a href="/rss2.xml"><img src="/img/rss.png" /></a>
+ <span>shading lights</span>
+ </p>
+ </header>
+
+ <section>
+ <div class="post">
+ <h1>
+ Java StringBuilder myth debunked -- now with content!
+ <a href="/2013/03/11/java-stringbuilder-myth-now-with-content">
+ <img src="/img/link.jpg" alt="Permalink to Java StringBuilder myth debunked -- now with content!" />
+ </a>
+</h1>
+<blockquote class="date-wrapper">
+ <h5 class="date">
+ March 11, 2013
+
+ &nbsp;
+
+ <a href="/category/java">#java</a><span>&nbsp;&nbsp;</span>
+
+ <a href="/category/performance">#performance</a><span>&nbsp;&nbsp;</span>
+
+ <a href="/category/development">#development</a><span>&nbsp;&nbsp;</span>
+
+
+ </h5>
+</blockquote>
+
+
+ <img src="/img/post/joint.png" class="primary" />
+
+ <h1>The myth</h1>
+
+<blockquote><p>Concatenating two Strings with the plus operator is the source of all evil</p>
+
+<p>-- Anonymous Java dev</p></blockquote>
+
+<p><em><strong>NOTE</strong>: The source code for the tests discussed here can be found on <a href="https://github.com/skuro/stringbuilder">Github</a></em></p>
+
+<p>It's from university time that I learned to regard <code>String</code> concatenation in Java
+using the '+' plus operator as a deadly performance sin. Recently there has been
+an internal review at <a href="http://www.backbase.com">Backbase R&amp;D</a> where such recurring
+mantra was dismissed as a myth due to <code>javac</code> using <code>StringBuilder</code> under the hood
+any time you use the plus operator to join Strings. I set myself up to prove
+such a point and verify the reality under different environments.</p>
+
+<h1>The test</h1>
+
+<p>Relying on your compiler to optimize your <code>String</code> concatenation means that things
+might change heavily depending on the JDK vendor you adopt. As far as platform
+support goes for my daily job, three main vendors should be considered:</p>
+
+<ul>
+<li>Oracle JDK</li>
+<li>IBM JDK</li>
+<li>ECJ -- for developers only</li>
+</ul>
+
+
+<p>Moreover, while we officially support Java 5 through 6, we are also looking into
+supporting Java 7 for our products, adding another three-folded level of indirection on top of
+the three vendors. For the sake of <del>lazyness</del> simplicity, the <code>ecj</code> compiled
+bytecode will be run with a single JDK, namely Oracle JDK7.</p>
+
+<p>I prepared a <a href="https://www.virtualbox.org/">Virtualbox</a> VM with all the above JDK
+installed, then I developed some classes to express three different concatenation
+methods, amounting to three to four concatenations per method invocaiton,
+depending on the specific test case.</p>
+
+<p>The test classes are run a thousands times for each test round, with a total of
+100 rounds each test case. The same VM is used to run all the rounds for the same
+test case, and it's restarted across different test cases, all to let the Java
+runtime perform all the optimizations it can, without affecting the other test
+cases in any way. The default options were used to start all JVMs.</p>
+
+<p>More details can be found in the benchmark runner <a href="https://github.com/skuro/stringbuilder/blob/master/bench.sh">script</a>.</p>
+
+<h1>The code</h1>
+
+<p>Full code for both test cases and the test suite is available on <a href="https://github.com/skuro/stringbuilder">Github</a>.</p>
+
+<p>The following different test cases were produced to measure performance
+differences of the String concatenation with plus against the direct use of a
+<code>StringBuilder</code>:</p>
+
+<pre><code>// String concat with plus
+String result = "const1" + base;
+result = result + "const2";
+</code></pre>
+
+<hr />
+
+<pre><code>// String concat with a StringBuilder
+new StringBuilder()
+ .append("const1")
+ .append(base)
+ .append("const2")
+ .append(append)
+ .toString();
+}
+</code></pre>
+
+<hr />
+
+<pre><code>//String concat with an initialized StringBuilder
+new StringBuilder("const1")
+ .append(base)
+ .append("const2")
+ .append(append)
+ .toString();
+</code></pre>
+
+<p>The general idea is to provide a concatenation both at the head and at the tail
+of constant <code>String</code>s over a variable. The difference between the last two cases,
+both making explicit use of <code>StringBuilder</code>, is in the latter using the 1-arg
+constructor which initializes the builder with the initial part of the result.</p>
+
+<h1>The results</h1>
+
+<p>Enough talking, down below here you can have a look at the generated graphs, where
+each data point corresponds to a single test round (e.g. 1000 executions of the same
+test class).</p>
+
+<p>The discussion of the results and some more juicy details will follow.</p>
+
+<h2><img src="img/post/catplus.png" title="Concatenation with plus" alt="Concatenation with plus" /></h2>
+
+<h2><img src="img/post/catsb.png" title="Concatenation with StringBuilder" alt="Concatenation with StringBuilder" /></h2>
+
+<p><img src="img/post/catsb2.png" title="Concatenation with initalized StringBuilder" alt="Concatenation with initialized StringBuilder" /></p>
+
+<h1>The discussion</h1>
+
+<p>Oracle JKD5 is the clear loser here, appearing to be in a B league when compared
+to the others. But that's not really the scope of this exercise, and thus we'll
+gloss over it for the time being.</p>
+
+<p>That said, there are two other interesting bits I observe in the above graph. The first is that indeed
+there is generally quite a difference between the use of the plus operator vs an explicit
+<code>StringBuilder</code>, <em>especially</em> if you're using Oracle Java5 which performs tree
+times worse the the rest of the crew.</p>
+
+<p>The second observation is that while it generally holds for most of the JDKs that
+an explicit <code>StringBuilder</code> will offer up to twice the speed as the regular plus
+operator, <strong>IBM JDK6 seems not to suffer</strong> from any performance loss, always averaging
+25ms to complete the task in all test cases.</p>
+
+<p>A closer look at the generated bytecode reveals some interesting details</p>
+
+<h1>The bytecode</h1>
+
+<p><em><strong>NOTE:</strong> the decompiled classes are also available on <a href="https://github.com/skuro/stringbuilder">Github</a></em></p>
+
+<p>Across all possible JDKs <code>StringBuilders</code> are <strong>always</strong> used to implement <code>String</code>
+concatenation even in presence of a plus sign.
+Moreover, across all vendors and versions, <strong>there is almost no difference at all</strong>
+for the same test case. The only one that stands a bit apart is <a href="https://github.com/skuro/stringbuilder/blob/master/ecj/CatPlus.class.txt"><code>ecj</code></a>,
+which is the only one to cleverly optimize the <code>CatPlus</code> test case to invoke
+the 1-arg constructor of the <code>StringBuilder</code> instead of the 0-arg version.</p>
+
+<p>Comparing the resulting bytecode exposes what could affect performance in the
+different scnarios:</p>
+
+<ul>
+<li><p>when concatenating with plus, <em>new instances of <code>StringBuilder</code></em> are created
+any time a concatenation happens. This can easily result in a performance
+degradation due to useless invocation of the constructor plus more stress on
+the garbage collector due to throw away instances</p></li>
+<li><p>compilers will take you literally and only initalize <code>StringBuilder</code> with its
+1-arg constructor if and only if you write it that way in the original code. This
+results in respectively four and three invocations of <code>StringBuilder.append</code> for
+<a href="https://github.com/skuro/stringbuilder/blob/master/ecj/CatSB.class.txt">CatSB</a> and <a href="https://github.com/skuro/stringbuilder/blob/master/ecj/CatSB2.class.txt">CatSB2</a>.</p></li>
+</ul>
+
+
+<h1>The conclusion</h1>
+
+<p>Bytecode analysis offers the final answer to the original question.</p>
+
+<blockquote><p>Do you need to explicitly use a <code>StringBuilder</code> to improve performance? <strong>Yes</strong></p></blockquote>
+
+<p>The above graphs clearly show that, unless you're using IBM JDK6 runtime, you will
+loss 50% performance when using the plus operator, although it's the one to perform
+slightly worse across the candidates when expliciting <code>StringBuffers</code>.</p>
+
+<p>Also, it's quite interesting to see how <em>JIT optimizations</em> impact the overall
+performance: for instance, even in presence of different bytecode between the two
+explicit <code>StringBuilder</code> test cases, the end result is absolutely the same in the
+long run.</p>
+
+<p><img src="img/post/myth-confirmed.jpg" alt="Myth confirmed" /></p>
+
+
+ <div id="disqus_thread"></div>
+<script type="text/javascript">
+ /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
+ var disqus_shortname = 'skuro';
+// var disqus_id = '/2013/03/11/java-stringbuilder-myth-now-with-content';
+// var disqus_url = [location.protocol, '//', location.host, location.pathname].join('');
+
+ /* * * DON'T EDIT BELOW THIS LINE * * */
+ (function() {
+ var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
+ dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+ })();
+</script>
+<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
+<a href="http://disqus.com" class="dsq-brlink">blog comments powered by <span class="logo-disqus">Disqus</span></a>
+
+
+
+</div>
+
+ </section>
+
+ </div>
+ <footer>
+ <p><a href="http://creativecommons.org/licenses/by-sa/3.0/" rel="license"><img src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" style="border-width:0;margin-bottom:10px" alt="Creative Commons License" /></a> licensed under a Creative Commons <a href="http://creativecommons.org/licenses/by-sa/3.0/" rel="license">license</a>
+ <p><span rel="dct:type" property="dct:title" href="http://purl.org/dc/dcmitype/Text">SKURO! blog</span> by <a rel="cc:attributionURL" property="cc:attributionName" href="http://skuro.tk">Carlo Sciolla</a></p>
+ </footer>
+
+ <script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+ </script>
+ <script type="text/javascript">
+ try{
+ var pageTracker = _gat._getTracker("UA-6754361-1");
+ pageTracker._trackPageview();
+ } catch(err) {}
+ </script>
+
+ </body>
+</html>
View
15 archive/index.html
@@ -56,6 +56,21 @@
<ul>
<li>
+ <span class="date">11 March 2013</span>
+ <a href="/2013/03/11/java-stringbuilder-myth-now-with-content">Java StringBuilder myth debunked -- now with content!</a>
+ <span class="categories">
+
+ <a class="tag" href="/category/java">#java</a>
+
+ <a class="tag" href="/category/performance">#performance</a>
+
+ <a class="tag" href="/category/development">#development</a>
+
+ </span>
+</li>
+
+
+ <li>
<span class="date">10 March 2013</span>
<a href="/2013/03/10/observer-pattern-spring-framework">The Observer Pattern in Spring</a>
<span class="categories">
View
2 category/developer/clojure/feed
@@ -3,7 +3,7 @@
<title type="text" xml:lang="en">SKURO! -- Shading lights</title>
<link type="application/atom+xml" href="http://skuro.tk/rss2/" rel="self"/>
<link type="text" href="http://skuro.tk" rel="alternate"/>
- <updated>2013-03-10T00:10:08+01:00</updated>
+ <updated>2013-03-11T23:43:59+01:00</updated>
<id>http://skuro.tk</id>
<author>
<name>Carlo Sciolla</name>
View
15 category/development/index.html
@@ -89,6 +89,21 @@ <h1 class="title">
</li>
+ <li>
+ <span class="date">11 March 2013</span>
+ <a href="/2013/03/11/java-stringbuilder-myth-now-with-content">Java StringBuilder myth debunked -- now with content!</a>
+ <span class="categories">
+
+ <a class="tag" href="/category/java">#java</a>
+
+ <a class="tag" href="/category/performance">#performance</a>
+
+ <a class="tag" href="/category/development">#development</a>
+
+ </span>
+</li>
+
+
</ul>
</div>
</div>
View
54 category/index.html
@@ -54,63 +54,63 @@
<h1>Categories</h1>
<div>
- <a class="tag" href="/category/windows/" style="font-size:23px">#windows</a>
-
- <a class="tag" href="/category/meetup/" style="font-size:35px">#meetup</a>
+ <a class="tag" href="/category/performance/" style="font-size:26px">#performance</a>
- <a class="tag" href="/category/presentation/" style="font-size:23px">#presentation</a>
+ <a class="tag" href="/category/alfresco/" style="font-size:59px">#alfresco</a>
- <a class="tag" href="/category/linux/" style="font-size:38px">#linux</a>
+ <a class="tag" href="/category/blog/" style="font-size:35px">#blog</a>
<a class="tag" href="/category/software/" style="font-size:23px">#software</a>
- <a class="tag" href="/category/h2support/" style="font-size:23px">#h2support</a>
+ <a class="tag" href="/category/development/" style="font-size:29px">#development</a>
- <a class="tag" href="/category/performance/" style="font-size:23px">#performance</a>
+ <a class="tag" href="/category/windows/" style="font-size:23px">#windows</a>
- <a class="tag" href="/category/orgmode/" style="font-size:23px">#orgmode</a>
+ <a class="tag" href="/category/amsterdam/" style="font-size:29px">#amsterdam</a>
- <a class="tag" href="/category/maven/" style="font-size:32px">#maven</a>
+ <a class="tag" href="/category/patterns/" style="font-size:23px">#patterns</a>
- <a class="tag" href="/category/alfresco/" style="font-size:59px">#alfresco</a>
+ <a class="tag" href="/category/orgmode/" style="font-size:23px">#orgmode</a>
- <a class="tag" href="/category/spring/" style="font-size:23px">#spring</a>
+ <a class="tag" href="/category/presentation/" style="font-size:23px">#presentation</a>
- <a class="tag" href="/category/amsterdam/" style="font-size:29px">#amsterdam</a>
+ <a class="tag" href="/category/meetup/" style="font-size:35px">#meetup</a>
- <a class="tag" href="/category/jira/" style="font-size:23px">#jira</a>
+ <a class="tag" href="/category/apple/" style="font-size:32px">#apple</a>
- <a class="tag" href="/category/emacs/" style="font-size:26px">#emacs</a>
+ <a class="tag" href="/category/jira/" style="font-size:23px">#jira</a>
- <a class="tag" href="/category/javascript/" style="font-size:26px">#javascript</a>
+ <a class="tag" href="/category/slides/" style="font-size:23px">#slides</a>
- <a class="tag" href="/category/java/" style="font-size:29px">#java</a>
+ <a class="tag" href="/category/maven/" style="font-size:32px">#maven</a>
- <a class="tag" href="/category/patterns/" style="font-size:23px">#patterns</a>
+ <a class="tag" href="/category/sonatype/" style="font-size:26px">#sonatype</a>
- <a class="tag" href="/category/slides/" style="font-size:23px">#slides</a>
+ <a class="tag" href="/category/italian/" style="font-size:26px">#italian</a>
- <a class="tag" href="/category/sonatype/" style="font-size:26px">#sonatype</a>
+ <a class="tag" href="/category/linux/" style="font-size:38px">#linux</a>
<a class="tag" href="/category/h2-support/" style="font-size:32px">#h2-support</a>
+ <a class="tag" href="/category/eclipse/" style="font-size:23px">#eclipse</a>
+
+ <a class="tag" href="/category/h2support/" style="font-size:23px">#h2support</a>
+
+ <a class="tag" href="/category/alm/" style="font-size:53px">#alm</a>
+
<a class="tag" href="/category/clojure/" style="font-size:50px">#clojure</a>
- <a class="tag" href="/category/development/" style="font-size:26px">#development</a>
+ <a class="tag" href="/category/javascript/" style="font-size:26px">#javascript</a>
- <a class="tag" href="/category/apple/" style="font-size:32px">#apple</a>
+ <a class="tag" href="/category/java/" style="font-size:32px">#java</a>
- <a class="tag" href="/category/blog/" style="font-size:35px">#blog</a>
+ <a class="tag" href="/category/spring/" style="font-size:23px">#spring</a>
<a class="tag" href="/category/subversion/" style="font-size:23px">#subversion</a>
<a class="tag" href="/category/intellij/" style="font-size:23px">#intellij</a>
- <a class="tag" href="/category/italian/" style="font-size:26px">#italian</a>
-
- <a class="tag" href="/category/alm/" style="font-size:53px">#alm</a>
-
- <a class="tag" href="/category/eclipse/" style="font-size:23px">#eclipse</a>
+ <a class="tag" href="/category/emacs/" style="font-size:26px">#emacs</a>
</div>
</section>
View
15 category/java/index.html
@@ -98,6 +98,21 @@ <h1 class="title">
</li>
+ <li>
+ <span class="date">11 March 2013</span>
+ <a href="/2013/03/11/java-stringbuilder-myth-now-with-content">Java StringBuilder myth debunked -- now with content!</a>
+ <span class="categories">
+
+ <a class="tag" href="/category/java">#java</a>
+
+ <a class="tag" href="/category/performance">#performance</a>
+
+ <a class="tag" href="/category/development">#development</a>
+
+ </span>
+</li>
+
+
</ul>
</div>
</div>
View
15 category/performance/index.html
@@ -72,6 +72,21 @@ <h1 class="title">
</li>
+ <li>
+ <span class="date">11 March 2013</span>
+ <a href="/2013/03/11/java-stringbuilder-myth-now-with-content">Java StringBuilder myth debunked -- now with content!</a>
+ <span class="categories">
+
+ <a class="tag" href="/category/java">#java</a>
+
+ <a class="tag" href="/category/performance">#performance</a>
+
+ <a class="tag" href="/category/development">#development</a>
+
+ </span>
+</li>
+
+
</ul>
</div>
</div>
View
BIN img/post/catmulti.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN img/post/catplus.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN img/post/catsb.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN img/post/catsb2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN img/post/joint.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN img/post/myth-confirmed.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
196 index.html
@@ -56,22 +56,22 @@
<!-- copied from post_header include -->
<h1>
- The Observer Pattern in Spring
- <a href="/2013/03/10/observer-pattern-spring-framework">
- <img src="/img/link.jpg" alt="Permalink to The Observer Pattern in Spring" />
+ Java StringBuilder myth debunked -- now with content!
+ <a href="/2013/03/11/java-stringbuilder-myth-now-with-content">
+ <img src="/img/link.jpg" alt="Permalink to Java StringBuilder myth debunked -- now with content!" />
</a>
</h1>
<blockquote class="date-wrapper">
<h5 class="date">
- March 10, 2013
+ March 11, 2013
&nbsp;
<a class="tag" href="/category/java">#java</a><span>&nbsp;&nbsp;</span>
- <a class="tag" href="/category/spring">#spring</a><span>&nbsp;&nbsp;</span>
+ <a class="tag" href="/category/performance">#performance</a><span>&nbsp;&nbsp;</span>
- <a class="tag" href="/category/patterns">#patterns</a><span>&nbsp;&nbsp;</span>
+ <a class="tag" href="/category/development">#development</a><span>&nbsp;&nbsp;</span>
</h5>
@@ -79,62 +79,168 @@ <h5 class="date">
<!-- end copy -->
- <img src="http://mimg.ugo.com/200907/10229/cuts/the-observer_288x288.jpg" class="primary" />
+ <img src="/img/post/joint.png" class="primary" />
- <h1>Observers in Spring</h1>
+ <h1>The myth</h1>
-<blockquote><p>To the man-in-the-street, who, I'm sorry to say,<br/>
-Is a keen observer of life,<br/>
-The word "Intellectual" suggests straight away<br/>
-A man who's untrue to his wife.</p>
+<blockquote><p>Concatenating two Strings with the plus operator is the source of all evil</p>
-<p>-- W.H. Auden</p></blockquote>
+<p>-- Anonymous Java dev</p></blockquote>
-<p>The Observer pattern is a very basic one out of the GoF bible which is unbelivably easy to implement and still quote
-powerful so use. Here I present my take on it using the Spring observer pattern which I found quite helpful in designing
-extension points for my software.</p>
+<p><em><strong>NOTE</strong>: The source code for the tests discussed here can be found on <a href="https://github.com/skuro/stringbuilder">Github</a></em></p>
-<h1>Core classes</h1>
+<p>It's from university time that I learned to regard <code>String</code> concatenation in Java
+using the '+' plus operator as a deadly performance sin. Recently there has been
+an internal review at <a href="http://www.backbase.com">Backbase R&amp;D</a> where such recurring
+mantra was dismissed as a myth due to <code>javac</code> using <code>StringBuilder</code> under the hood
+any time you use the plus operator to join Strings. I set myself up to prove
+such a point and verify the reality under different environments.</p>
-<p>Pushing back the little NIH devil whispering in my ears, I started by reusing the standard building blocks for the
-Observer pattern: <code>java.util.Observable</code> and <code>java.util.Observer</code>. The Observable class provides the logic to handle a
-registry of Observers, and to propagate updates (I prefer to think more of in terms of events) to all of the registered
-Observers.</p>
+<h1>The test</h1>
-<p>In the context of a Spring container, there will be beans to configure and hook together, and it's key to this exercise
-to find a flexible and handy way to connect things together.</p>
+<p>Relying on your compiler to optimize your <code>String</code> concatenation means that things
+might change heavily depending on the JDK vendor you adopt. As far as platform
+support goes for my daily job, three main vendors should be considered:</p>
-<h1>Automatic registration</h1>
+<ul>
+<li>Oracle JDK</li>
+<li>IBM JDK</li>
+<li>ECJ -- for developers only</li>
+</ul>
-<p>Supporting code for this blog post can be found on <a href="https://github.com/skuro/spring-observer">GitHub</a>.</p>
-<p>When developing a Spring application you're always instantiating your classes as singletons within the Spring container.
-Annotations or XML configurations will take care of initialize instances of your classes, wiring them together in a
-connected graph of objects with loose dependencies on the specific concrete classes you adopt in your code.</p>
+<p>Moreover, while we officially support Java 5 through 6, we are also looking into
+supporting Java 7 for our products, adding another three-folded level of indirection on top of
+the three vendors. For the sake of <del>lazyness</del> simplicity, the <code>ecj</code> compiled
+bytecode will be run with a single JDK, namely Oracle JDK7.</p>
-<p>As you will always have to declare beans, it would be nice to let Spring wire obects for you in an Observer fashion,
-with a minimal coding effort required. The most minimalistic approach I could think of is to just require developers to
-declare their observer beans, and put in place enough machinery to automatically hook them to an Observable provided by
-the application. In this example I create a <code>ObserverBeanPostProcessor</code> and a <code>SpringObserver</code>
-tagging interface to identify which beans are actually declaring valid Observers, and register them automatically.</p>
+<p>I prepared a <a href="https://www.virtualbox.org/">Virtualbox</a> VM with all the above JDK
+installed, then I developed some classes to express three different concatenation
+methods, amounting to three to four concatenations per method invocaiton,
+depending on the specific test case.</p>
-<p>To complete the picture, the <code>SpringObservable</code> interface declares which <code>Observer</code> class it's able to notify, thus
-leveraging the tagging interface and letting the <code>ObserverBeanPostProcessor</code> know which beans to filter and registser.</p>
+<p>The test classes are run a thousands times for each test round, with a total of
+100 rounds each test case. The same VM is used to run all the rounds for the same
+test case, and it's restarted across different test cases, all to let the Java
+runtime perform all the optimizations it can, without affecting the other test
+cases in any way. The default options were used to start all JVMs.</p>
-<p>This enables a software component to provide the desired <code>SpringObservable</code> and the <code>ObserverBeanPostProcessor</code> beans, where
-consumers of such API will be only required to instantiate their <code>Observer</code> beans.</p>
+<p>More details can be found in the benchmark runner <a href="https://github.com/skuro/stringbuilder/blob/master/bench.sh">script</a>.</p>
-<p>Note that <code>Observers</code> can be themselves <code>Observables</code>, so that you can easily construct chains of beans in which events
-will be propagated. As long as you ensure not to form any cyclic graph, of course.</p>
+<h1>The code</h1>
-<h1>Conclusions</h1>
+<p>Full code for both test cases and the test suite is available on <a href="https://github.com/skuro/stringbuilder">Github</a>.</p>
-<p>In object oriented languages such as Java, patterns are a powerful tool to apply. The Observer is a neat strategy for
-cascading changes on objects, or just to propagate events through a series of processors. All in a clean, loosly coupled
-fashion.</p>
+<p>The following different test cases were produced to measure performance
+differences of the String concatenation with plus against the direct use of a
+<code>StringBuilder</code>:</p>
-<p>The code here is just a proof of concept, not a library which is intended for production use. The concepts and the
-implementation are easy enough to be applied in your Spring application without any need for depending on this code.</p>
+<pre><code>// String concat with plus
+String result = "const1" + base;
+result = result + "const2";
+</code></pre>
+
+<hr />
+
+<pre><code>// String concat with a StringBuilder
+new StringBuilder()
+ .append("const1")
+ .append(base)
+ .append("const2")
+ .append(append)
+ .toString();
+}
+</code></pre>
+
+<hr />
+
+<pre><code>//String concat with an initialized StringBuilder
+new StringBuilder("const1")
+ .append(base)
+ .append("const2")
+ .append(append)
+ .toString();
+</code></pre>
+
+<p>The general idea is to provide a concatenation both at the head and at the tail
+of constant <code>String</code>s over a variable. The difference between the last two cases,
+both making explicit use of <code>StringBuilder</code>, is in the latter using the 1-arg
+constructor which initializes the builder with the initial part of the result.</p>
+
+<h1>The results</h1>
+
+<p>Enough talking, down below here you can have a look at the generated graphs, where
+each data point corresponds to a single test round (e.g. 1000 executions of the same
+test class).</p>
+
+<p>The discussion of the results and some more juicy details will follow.</p>
+
+<h2><img src="img/post/catplus.png" title="Concatenation with plus" alt="Concatenation with plus" /></h2>
+
+<h2><img src="img/post/catsb.png" title="Concatenation with StringBuilder" alt="Concatenation with StringBuilder" /></h2>
+
+<p><img src="img/post/catsb2.png" title="Concatenation with initalized StringBuilder" alt="Concatenation with initialized StringBuilder" /></p>
+
+<h1>The discussion</h1>
+
+<p>Oracle JKD5 is the clear loser here, appearing to be in a B league when compared
+to the others. But that's not really the scope of this exercise, and thus we'll
+gloss over it for the time being.</p>
+
+<p>That said, there are two other interesting bits I observe in the above graph. The first is that indeed
+there is generally quite a difference between the use of the plus operator vs an explicit
+<code>StringBuilder</code>, <em>especially</em> if you're using Oracle Java5 which performs tree
+times worse the the rest of the crew.</p>
+
+<p>The second observation is that while it generally holds for most of the JDKs that
+an explicit <code>StringBuilder</code> will offer up to twice the speed as the regular plus
+operator, <strong>IBM JDK6 seems not to suffer</strong> from any performance loss, always averaging
+25ms to complete the task in all test cases.</p>
+
+<p>A closer look at the generated bytecode reveals some interesting details</p>
+
+<h1>The bytecode</h1>
+
+<p><em><strong>NOTE:</strong> the decompiled classes are also available on <a href="https://github.com/skuro/stringbuilder">Github</a></em></p>
+
+<p>Across all possible JDKs <code>StringBuilders</code> are <strong>always</strong> used to implement <code>String</code>
+concatenation even in presence of a plus sign.
+Moreover, across all vendors and versions, <strong>there is almost no difference at all</strong>
+for the same test case. The only one that stands a bit apart is <a href="https://github.com/skuro/stringbuilder/blob/master/ecj/CatPlus.class.txt"><code>ecj</code></a>,
+which is the only one to cleverly optimize the <code>CatPlus</code> test case to invoke
+the 1-arg constructor of the <code>StringBuilder</code> instead of the 0-arg version.</p>
+
+<p>Comparing the resulting bytecode exposes what could affect performance in the
+different scnarios:</p>
+
+<ul>
+<li><p>when concatenating with plus, <em>new instances of <code>StringBuilder</code></em> are created
+any time a concatenation happens. This can easily result in a performance
+degradation due to useless invocation of the constructor plus more stress on
+the garbage collector due to throw away instances</p></li>
+<li><p>compilers will take you literally and only initalize <code>StringBuilder</code> with its
+1-arg constructor if and only if you write it that way in the original code. This
+results in respectively four and three invocations of <code>StringBuilder.append</code> for
+<a href="https://github.com/skuro/stringbuilder/blob/master/ecj/CatSB.class.txt">CatSB</a> and <a href="https://github.com/skuro/stringbuilder/blob/master/ecj/CatSB2.class.txt">CatSB2</a>.</p></li>
+</ul>
+
+
+<h1>The conclusion</h1>
+
+<p>Bytecode analysis offers the final answer to the original question.</p>
+
+<blockquote><p>Do you need to explicitly use a <code>StringBuilder</code> to improve performance? <strong>Yes</strong></p></blockquote>
+
+<p>The above graphs clearly show that, unless you're using IBM JDK6 runtime, you will
+loss 50% performance when using the plus operator, although it's the one to perform
+slightly worse across the candidates when expliciting <code>StringBuffers</code>.</p>
+
+<p>Also, it's quite interesting to see how <em>JIT optimizations</em> impact the overall
+performance: for instance, even in presence of different bytecode between the two
+explicit <code>StringBuilder</code> test cases, the end result is absolutely the same in the
+long run.</p>
+
+<p><img src="img/post/myth-confirmed.jpg" alt="Myth confirmed" /></p>
</div>
View
196 rss2.xml
@@ -3,7 +3,7 @@
<title type="text" xml:lang="en">SKURO! -- Shading lights</title>
<link type="application/atom+xml" href="http://skuro.tk/rss2/" rel="self"/>
<link type="text" href="http://skuro.tk" rel="alternate"/>
- <updated>2013-03-10T00:10:08+01:00</updated>
+ <updated>2013-03-11T23:43:59+01:00</updated>
<id>http://skuro.tk</id>
<author>
<name>Carlo Sciolla</name>
@@ -11,6 +11,175 @@
<rights>Copyright (c) 2010-2011 Carlo Sciolla</rights>
<entry>
+ <title>Java StringBuilder myth debunked -- now with content!</title>
+ <link href="http://skuro.tk/2013/03/11/java-stringbuilder-myth-now-with-content/"/>
+ <updated>2013-03-11T00:00:00+01:00</updated>
+ <id>http://skuro.tk/2013/03/11/java-stringbuilder-myth-now-with-content/</id>
+ <summary type="html">&lt;h1&gt;The myth&lt;/h1&gt;
+
+&lt;blockquote&gt;&lt;p&gt;Concatenating two Strings with the plus operator is the source of all evil&lt;/p&gt;
+
+&lt;p&gt;-- Anonymous Java dev&lt;/p&gt;&lt;/blockquote&gt;
+
+&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: The source code for the tests discussed here can be found on &lt;a href=&quot;https://github.com/skuro/stringbuilder&quot;&gt;Github&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
+
+&lt;p&gt;It's from university time that I learned to regard &lt;code&gt;String&lt;/code&gt; concatenation in Java
+using the '+' plus operator as a deadly performance sin. Recently there has been
+an internal review at &lt;a href=&quot;http://www.backbase.com&quot;&gt;Backbase R&amp;amp;D&lt;/a&gt; where such recurring
+mantra was dismissed as a myth due to &lt;code&gt;javac&lt;/code&gt; using &lt;code&gt;StringBuilder&lt;/code&gt; under the hood
+any time you use the plus operator to join Strings. I set myself up to prove
+such a point and verify the reality under different environments.&lt;/p&gt;
+
+&lt;h1&gt;The test&lt;/h1&gt;
+
+&lt;p&gt;Relying on your compiler to optimize your &lt;code&gt;String&lt;/code&gt; concatenation means that things
+might change heavily depending on the JDK vendor you adopt. As far as platform
+support goes for my daily job, three main vendors should be considered:&lt;/p&gt;
+
+&lt;ul&gt;
+&lt;li&gt;Oracle JDK&lt;/li&gt;
+&lt;li&gt;IBM JDK&lt;/li&gt;
+&lt;li&gt;ECJ -- for developers only&lt;/li&gt;
+&lt;/ul&gt;
+
+
+&lt;p&gt;Moreover, while we officially support Java 5 through 6, we are also looking into
+supporting Java 7 for our products, adding another three-folded level of indirection on top of
+the three vendors. For the sake of &lt;del&gt;lazyness&lt;/del&gt; simplicity, the &lt;code&gt;ecj&lt;/code&gt; compiled
+bytecode will be run with a single JDK, namely Oracle JDK7.&lt;/p&gt;
+
+&lt;p&gt;I prepared a &lt;a href=&quot;https://www.virtualbox.org/&quot;&gt;Virtualbox&lt;/a&gt; VM with all the above JDK
+installed, then I developed some classes to express three different concatenation
+methods, amounting to three to four concatenations per method invocaiton,
+depending on the specific test case.&lt;/p&gt;
+
+&lt;p&gt;The test classes are run a thousands times for each test round, with a total of
+100 rounds each test case. The same VM is used to run all the rounds for the same
+test case, and it's restarted across different test cases, all to let the Java
+runtime perform all the optimizations it can, without affecting the other test
+cases in any way. The default options were used to start all JVMs.&lt;/p&gt;
+
+&lt;p&gt;More details can be found in the benchmark runner &lt;a href=&quot;https://github.com/skuro/stringbuilder/blob/master/bench.sh&quot;&gt;script&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h1&gt;The code&lt;/h1&gt;
+
+&lt;p&gt;Full code for both test cases and the test suite is available on &lt;a href=&quot;https://github.com/skuro/stringbuilder&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;
+
+&lt;p&gt;The following different test cases were produced to measure performance
+differences of the String concatenation with plus against the direct use of a
+&lt;code&gt;StringBuilder&lt;/code&gt;:&lt;/p&gt;
+
+&lt;pre&gt;&lt;code&gt;// String concat with plus
+String result = &quot;const1&quot; + base;
+result = result + &quot;const2&quot;;
+&lt;/code&gt;&lt;/pre&gt;
+
+&lt;hr /&gt;
+
+&lt;pre&gt;&lt;code&gt;// String concat with a StringBuilder
+new StringBuilder()
+ .append(&quot;const1&quot;)
+ .append(base)
+ .append(&quot;const2&quot;)
+ .append(append)
+ .toString();
+}
+&lt;/code&gt;&lt;/pre&gt;
+
+&lt;hr /&gt;
+
+&lt;pre&gt;&lt;code&gt;//String concat with an initialized StringBuilder
+new StringBuilder(&quot;const1&quot;)
+ .append(base)
+ .append(&quot;const2&quot;)
+ .append(append)
+ .toString();
+&lt;/code&gt;&lt;/pre&gt;
+
+&lt;p&gt;The general idea is to provide a concatenation both at the head and at the tail
+of constant &lt;code&gt;String&lt;/code&gt;s over a variable. The difference between the last two cases,
+both making explicit use of &lt;code&gt;StringBuilder&lt;/code&gt;, is in the latter using the 1-arg
+constructor which initializes the builder with the initial part of the result.&lt;/p&gt;
+
+&lt;h1&gt;The results&lt;/h1&gt;
+
+&lt;p&gt;Enough talking, down below here you can have a look at the generated graphs, where
+each data point corresponds to a single test round (e.g. 1000 executions of the same
+test class).&lt;/p&gt;
+
+&lt;p&gt;The discussion of the results and some more juicy details will follow.&lt;/p&gt;
+
+&lt;h2&gt;&lt;img src=&quot;img/post/catplus.png&quot; title=&quot;Concatenation with plus&quot; alt=&quot;Concatenation with plus&quot; /&gt;&lt;/h2&gt;
+
+&lt;h2&gt;&lt;img src=&quot;img/post/catsb.png&quot; title=&quot;Concatenation with StringBuilder&quot; alt=&quot;Concatenation with StringBuilder&quot; /&gt;&lt;/h2&gt;
+
+&lt;p&gt;&lt;img src=&quot;img/post/catsb2.png&quot; title=&quot;Concatenation with initalized StringBuilder&quot; alt=&quot;Concatenation with initialized StringBuilder&quot; /&gt;&lt;/p&gt;
+
+&lt;h1&gt;The discussion&lt;/h1&gt;
+
+&lt;p&gt;Oracle JKD5 is the clear loser here, appearing to be in a B league when compared
+to the others. But that's not really the scope of this exercise, and thus we'll
+gloss over it for the time being.&lt;/p&gt;
+
+&lt;p&gt;That said, there are two other interesting bits I observe in the above graph. The first is that indeed
+there is generally quite a difference between the use of the plus operator vs an explicit
+&lt;code&gt;StringBuilder&lt;/code&gt;, &lt;em&gt;especially&lt;/em&gt; if you're using Oracle Java5 which performs tree
+times worse the the rest of the crew.&lt;/p&gt;
+
+&lt;p&gt;The second observation is that while it generally holds for most of the JDKs that
+an explicit &lt;code&gt;StringBuilder&lt;/code&gt; will offer up to twice the speed as the regular plus
+operator, &lt;strong&gt;IBM JDK6 seems not to suffer&lt;/strong&gt; from any performance loss, always averaging
+25ms to complete the task in all test cases.&lt;/p&gt;
+
+&lt;p&gt;A closer look at the generated bytecode reveals some interesting details&lt;/p&gt;
+
+&lt;h1&gt;The bytecode&lt;/h1&gt;
+
+&lt;p&gt;&lt;em&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; the decompiled classes are also available on &lt;a href=&quot;https://github.com/skuro/stringbuilder&quot;&gt;Github&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
+
+&lt;p&gt;Across all possible JDKs &lt;code&gt;StringBuilders&lt;/code&gt; are &lt;strong&gt;always&lt;/strong&gt; used to implement &lt;code&gt;String&lt;/code&gt;
+concatenation even in presence of a plus sign.
+Moreover, across all vendors and versions, &lt;strong&gt;there is almost no difference at all&lt;/strong&gt;
+for the same test case. The only one that stands a bit apart is &lt;a href=&quot;https://github.com/skuro/stringbuilder/blob/master/ecj/CatPlus.class.txt&quot;&gt;&lt;code&gt;ecj&lt;/code&gt;&lt;/a&gt;,
+which is the only one to cleverly optimize the &lt;code&gt;CatPlus&lt;/code&gt; test case to invoke
+the 1-arg constructor of the &lt;code&gt;StringBuilder&lt;/code&gt; instead of the 0-arg version.&lt;/p&gt;
+
+&lt;p&gt;Comparing the resulting bytecode exposes what could affect performance in the
+different scnarios:&lt;/p&gt;
+
+&lt;ul&gt;
+&lt;li&gt;&lt;p&gt;when concatenating with plus, &lt;em&gt;new instances of &lt;code&gt;StringBuilder&lt;/code&gt;&lt;/em&gt; are created
+any time a concatenation happens. This can easily result in a performance
+degradation due to useless invocation of the constructor plus more stress on
+the garbage collector due to throw away instances&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;compilers will take you literally and only initalize &lt;code&gt;StringBuilder&lt;/code&gt; with its
+1-arg constructor if and only if you write it that way in the original code. This
+results in respectively four and three invocations of &lt;code&gt;StringBuilder.append&lt;/code&gt; for
+&lt;a href=&quot;https://github.com/skuro/stringbuilder/blob/master/ecj/CatSB.class.txt&quot;&gt;CatSB&lt;/a&gt; and &lt;a href=&quot;https://github.com/skuro/stringbuilder/blob/master/ecj/CatSB2.class.txt&quot;&gt;CatSB2&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+
+&lt;h1&gt;The conclusion&lt;/h1&gt;
+
+&lt;p&gt;Bytecode analysis offers the final answer to the original question.&lt;/p&gt;
+
+&lt;blockquote&gt;&lt;p&gt;Do you need to explicitly use a &lt;code&gt;StringBuilder&lt;/code&gt; to improve performance? &lt;strong&gt;Yes&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;
+
+&lt;p&gt;The above graphs clearly show that, unless you're using IBM JDK6 runtime, you will
+loss 50% performance when using the plus operator, although it's the one to perform
+slightly worse across the candidates when expliciting &lt;code&gt;StringBuffers&lt;/code&gt;.&lt;/p&gt;
+
+&lt;p&gt;Also, it's quite interesting to see how &lt;em&gt;JIT optimizations&lt;/em&gt; impact the overall
+performance: for instance, even in presence of different bytecode between the two
+explicit &lt;code&gt;StringBuilder&lt;/code&gt; test cases, the end result is absolutely the same in the
+long run.&lt;/p&gt;
+
+&lt;p&gt;&lt;img src=&quot;img/post/myth-confirmed.jpg&quot; alt=&quot;Myth confirmed&quot; /&gt;&lt;/p&gt;
+</summary>
+</entry>
+
+
+<entry>
<title>The Observer Pattern in Spring</title>
<link href="http://skuro.tk/2013/03/10/observer-pattern-spring-framework/"/>
<updated>2013-03-10T00:00:00+01:00</updated>
@@ -78,7 +247,7 @@ implementation are easy enough to be applied in your Spring application without
<link href="http://skuro.tk/2013/03/06/java-stringbuilder-myth/"/>
<updated>2013-03-06T00:00:00+01:00</updated>
<id>http://skuro.tk/2013/03/06/java-stringbuilder-myth/</id>
- <summary type="html">
+ <summary type="html">&lt;p&gt;&lt;em&gt;NOTE: this post was published before it was ready, the real content can now be found &lt;a href=&quot;2013/03/11/java-stringbuilder-myth-now-with-content/&quot;&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</summary>
</entry>
@@ -827,28 +996,5 @@ Wednesday, October 12th we're going to have a great &lt;a href=&quot;http://bit.
</entry>
-<entry>
- <title>H2 embedded DB and Alfresco 3.4</title>
- <link href="http://skuro.tk/2011/08/03/h2-embedded-db-and-alfresco-3-4/"/>
- <updated>2011-08-03T00:00:00+02:00</updated>
- <id>http://skuro.tk/2011/08/03/h2-embedded-db-and-alfresco-3-4/</id>
- <summary type="html">&lt;p&gt;One of the most useful thing an embedded DB can do for you is to provide a clean environment in your automated tests to use as a clean slate where to repeatedly and reliably test your code. It's been a while since Alfresco &lt;a href=&quot;http://issues.alfresco.com/jira/browse/ALFCOM-3691&quot;&gt;broke compatibility&lt;/a&gt; with some embedded DB we used to run our tests (&lt;a href=&quot;http://hsqldb.org/&quot;&gt;HSQLDB&lt;/a&gt; above all others).&lt;/p&gt;
-
-&lt;p&gt;I recently regained interest into cutting out any useless dependency on MySQL or PostgreSQL on the test server to run my Alfresco tests, and H2 looked sexy. I found &lt;a href=&quot;http://www.codinginahurry.com/2010/11/27/running-alfresco-33-with-embedded-database-h2-in-postgresql-compability-mode/&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://issues.alfresco.com/jira/browse/ALF-3537&quot;&gt;there&lt;/a&gt; some promising work by other people, but none worked for me out of the box. I then started from scratch using PostgreSQL DB scripts and voila! Now I have back my Alfresco running against an embeddable DB! You can see &amp;amp; fork &lt;a href=&quot;http://bit.ly/nIJuLY&quot;&gt;the results&lt;/a&gt; of my job if you like. It's supposed to help you with a Maven Alfresco project, but you can probably benefit from it even if you're using some other build tools.&lt;/p&gt;
-
-&lt;p&gt;As soon as you have all those files in your classpath, be sure you edit your &lt;em&gt;alfresco-global.properties&lt;/em&gt; like the following:&lt;/p&gt;
-
-&lt;pre&gt;&lt;code&gt;db.driver=org.h2.Driver
-db.url=jdbc:h2:alf_data/h2_data/alfresco
-db.username=alfresco
-db.password=alfresco
-hibernate.dialect=org.hibernate.dialect.H2Dialect
-&lt;/code&gt;&lt;/pre&gt;
-
-&lt;p&gt;Make sure you're using an hibernate version &amp;gt;= 3.1 as per H2 &lt;a href=&quot;http://www.h2database.com/html/tutorial.html#using_hibernate&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
-</summary>
-</entry>
-
-
</feed>
View
16 sitemap.xml
@@ -3,7 +3,7 @@
<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://skuro.tk/</loc>
- <lastmod>2013-03-10T00:10:08+01:00</lastmod>
+ <lastmod>2013-03-11T23:43:59+01:00</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
@@ -15,6 +15,13 @@
</url>
<url>
+ <loc>http://skuro.tk/2013/03/11/java-stringbuilder-myth-now-with-content/</loc>
+ <lastmod>2013-03-11T00:00:00+01:00</lastmod>
+ <changefreq>weekly</changefreq>
+ <priority>0.8</priority>
+ </url>
+
+ <url>
<loc>http://skuro.tk/2013/03/10/observer-pattern-spring-framework/</loc>
<lastmod>2013-03-10T00:00:00+01:00</lastmod>
<changefreq>weekly</changefreq>
@@ -147,11 +154,4 @@
<priority>0.8</priority>
</url>
- <url>
- <loc>http://skuro.tk/2011/08/03/h2-embedded-db-and-alfresco-3-4/</loc>
- <lastmod>2011-08-03T00:00:00+02:00</lastmod>
- <changefreq>weekly</changefreq>
- <priority>0.8</priority>
- </url>
-
</urlset>

0 comments on commit f28aa60

Please sign in to comment.
Something went wrong with that request. Please try again.