{"id":6781,"date":"2019-10-24T09:00:24","date_gmt":"2019-10-24T07:00:24","guid":{"rendered":"https:\/\/www.happycoders.eu\/?p=6781"},"modified":"2024-12-02T12:02:06","modified_gmt":"2024-12-02T11:02:06","slug":"int-in-string-umwandeln-schnellster-weg","status":"publish","type":"post","link":"https:\/\/www.happycoders.eu\/de\/java\/int-in-string-umwandeln-schnellster-weg\/","title":{"rendered":"Java: int in String umwandeln \u2013 so geht's am schnellsten"},"content":{"rendered":"\n<p>In diesem Artikel zeige ich euch, wie ihr in Java am schnellsten ein int in einen String umwandelt. Die Antwort wird f\u00fcr einige sicher \u00fcberraschend sein. Ich stelle euch vier Varianten vor. Deren Geschwindkeit messe und vergleiche ich mit Hilfe von JMH-Microbenchmarks. Die Messergebnisse werde ich mit Hilfe des Java-Quellcodes und auch des erzeugten Bytecodes analysieren. Falls du die Details \u00fcberspringen m\u00f6chtest, <a href=\"#The_quickest_way\">kannst Du \u00fcber diesen Link direkt zum Ergebnis runterscrollen<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"varianten-fuer-die-int-to-string-konvertierung\">Varianten f\u00fcr die int-to-String-Konvertierung<\/h2>\n\n\n\n<p>Folgende vier Optionen gibt es (abgesehen von absichtlich komplizierter konstruierten Varianten):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Option 1: <code>Integer.toString(i)<\/code><\/li>\n\n\n\n<li>Option 2: <code>String.valueOf(i)<\/code><\/li>\n\n\n\n<li>Option 3: <code>String.format(\"%d\", i)<\/code><\/li>\n\n\n\n<li>Option 4: <code>\"\" + i<\/code><\/li>\n<\/ul>\n\n\n\n<p>Im Folgenden werde ich zun\u00e4chst ausf\u00fchrliche Benchmarks durchf\u00fchren und danach die Ergebnisse anhand des Java-Quellcodes und des erzeugten Bytecodes interpretieren.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"performance-messungen-der-int-zu-string-umwandlung\">Performance-Messungen der int-zu-String-Umwandlung<\/h2>\n\n\n\n<p>Um zu ermitteln, welche der Optionen die schnellste ist, habe ich Benchmarks mit dem <a rel=\"noopener\" href=\"https:\/\/openjdk.org\/projects\/code-tools\/jmh\/\" target=\"_blank\">Java Microbenchmark Harness<\/a> \u2013 kurz: <em>JMH<\/em> \u2013 durchgef\u00fchrt.<\/p>\n\n\n\n<p>Der JMH ist ein Framework, der Benchmark-Tests f\u00fcr kurze Code-Ausschnitte erm\u00f6glicht und aussagekr\u00e4ftige Messwerte im Milli-, Mikro- und Nanosekundenbereich liefert. Dazu werden die Tests hunderttausendfach wiederholt, und der eigentliche Messvorgang wird erst nach einer Aufw\u00e4rmphase gestartet, um dem Just-in-Time-Compiler ausreichend Vorlaufzeit f\u00fcr die Code-Optimierung zu gew\u00e4hren.<\/p>\n\n\n\n<p>Ein sehr gutes Einsteiger-Tutorial findet ihr auf <a rel=\"noreferrer noopener\" href=\"https:\/\/jenkov.com\/tutorials\/java-performance\/jmh.html\" target=\"_blank\">tutorials.jenkov.com<\/a>. <\/p>\n\n\n\n<p>IntelliJ kommt standardm\u00e4\u00dfig mit einem JMH-Plugin, so dass ihr die Benchmark-Tests direkt in der IDE ausf\u00fchren k\u00f6nnt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"quellcode-der-microbenchmarks\">Quellcode der Microbenchmarks<\/h3>\n\n\n\n<p>Im Folgenden findet ihr den kompletten Quellcode des int-to-String-Benchmarks. Ihr k\u00f6nnt den Code direkt in eure IDE kopieren oder ihn als Maven-Ptojekt aus meinem <a rel=\"noopener\" href=\"https:\/\/github.com\/SvenWoltmann\/int-to-string-benchmarks\" target=\"_blank\">GitHub-Repository<\/a> klonen. Wenn ihr selbst ein Projekt anlegt, m\u00fcsst ihr die folgenden zwei Dependencies hinzuf\u00fcgen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>JMH Core: <a rel=\"noopener\" href=\"https:\/\/mvnrepository.com\/artifact\/org.openjdk.jmh\/jmh-core\" target=\"_blank\">org.openjdk.jmh:jmh-core<\/a><\/li>\n\n\n\n<li>JMH Annotation Processor: <a rel=\"noopener\" href=\"https:\/\/mvnrepository.com\/artifact\/org.openjdk.jmh\/jmh-generator-annprocess\" target=\"_blank\">org.openjdk.jmh:jmh-generator-annprocess<\/a> (im Scope \"provided\")<\/li>\n<\/ul>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">package<\/span> eu.happycoders.int2string;\n\n<span class=\"hljs-keyword\">import<\/span> org.openjdk.jmh.annotations.*;\n<span class=\"hljs-keyword\">import<\/span> org.openjdk.jmh.infra.Blackhole;\n\n<span class=\"hljs-keyword\">import<\/span> java.util.concurrent.ThreadLocalRandom;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">IntToStringBenchmark<\/span> <\/span>{\n\n  <span class=\"hljs-meta\">@State<\/span>(Scope.Thread)\n  <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyState<\/span> <\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">int<\/span> i;\n\n    <span class=\"hljs-meta\">@Setup<\/span>(Level.Invocation)\n    <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">doSetup<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n      <span class=\"hljs-comment\">\/\/ always 7-digits, so that the String always has the same length<\/span>\n      i = <span class=\"hljs-number\">1_000_000<\/span> + ThreadLocalRandom.current().nextInt(<span class=\"hljs-number\">9_000_000<\/span>);\n    }\n  }\n\n  <span class=\"hljs-meta\">@Benchmark<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">option1<\/span><span class=\"hljs-params\">(MyState state, Blackhole blackhole)<\/span> <\/span>{\n    String s = Integer.toString(state.i);\n    blackhole.consume(s);\n  }\n\n  <span class=\"hljs-meta\">@Benchmark<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">option2<\/span><span class=\"hljs-params\">(MyState state, Blackhole blackhole)<\/span> <\/span>{\n    String s = String.valueOf(state.i);\n    blackhole.consume(s);\n  }\n\n  <span class=\"hljs-meta\">@Benchmark<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">option3<\/span><span class=\"hljs-params\">(MyState state, Blackhole blackhole)<\/span> <\/span>{\n    String s = String.format(<span class=\"hljs-string\">\"%d\"<\/span>, state.i);\n    blackhole.consume(s);\n  }\n\n  <span class=\"hljs-meta\">@Benchmark<\/span>\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">option4<\/span><span class=\"hljs-params\">(MyState state, Blackhole blackhole)<\/span> <\/span>{\n    String s = <span class=\"hljs-string\">\"\"<\/span> + state.i;\n    blackhole.consume(s);\n  }\n\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Ein paar Anmerkungen zum Quellcode:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Die int-Variable <code>i<\/code> belege ich mit einer Zufallszahl, damit sie nicht durch eine Konstante ersetzt und die komplette String-Umwandlung wegoptimiert wird.<\/li>\n\n\n\n<li>Die Erzeugung der Zufallszahl wird in die <code>setup()<\/code>-Methode eines sogenannten \"State\" ausgelagert, so dass die Ausf\u00fchrungszeit daf\u00fcr nicht mitgemessen wird.<\/li>\n\n\n\n<li>Durch die Annotation <code>@Setup(Level.<strong><em>Invocation<\/em><\/strong>)<\/code> wird die <code>setup()<\/code>-Methode vor jedem Aufruf der Testmethode ausgef\u00fchrt; somit erh\u00e4lt jeder Aufruf eine neue Zufallszahl.<\/li>\n\n\n\n<li>Das Konvertierungsergebnis wird jeweils dem <code>Blackhole<\/code> \u00fcbergeben \u2013 wiederum damit der Compiler die  Konvertierung nicht wegoptimiert.<\/li>\n<\/ul>\n\n\n<div class=\"convertkit-form wp-block-convertkit-form\" style=\"\"><script async data-uid=\"1427197203\" src=\"https:\/\/happycoders.kit.com\/1427197203\/index.js\" data-jetpack-boost=\"ignore\" data-no-defer=\"1\" data-no-optimize=\"1\" nowprocket><\/script><\/div>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"microbenchmark-ergebnisse\">Microbenchmark-Ergebnisse<\/h3>\n\n\n\n<p>Im Folgenden findet ihr die Messergebnisse auf meinem Dell XPS 15 9570 mit einem Intel Core i7-8750H. Detaillierte Messergebnisse (inkl. aller Einzeltests, Minima, Maxima und Standardabweichungen) findet ihr im <a href=\"https:\/\/github.com\/SvenWoltmann\/int-to-string-benchmarks\/tree\/main\/results\" target=\"_blank\" rel=\"noopener\"><tt>results\/<\/tt>-Verzeichnis meines GitHub-Repositorys<\/a>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Messergebnisse int-to-String mit Java 7<\/h4>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><td><strong>Methode<\/strong><\/td><td><strong>Operationen pro Sekunde<\/strong><\/td><td><strong>Konfidenz\u200b\u200bintervall (99,9 %)<\/strong><\/td><\/tr><tr><td><code>Integer.\u200b\u200btoString(i)<\/code><\/td><td>20.365.947<\/td><td>20.276.015 \u2013 20.455.879<\/td><\/tr><tr><td><code>String.\u200b\u200bvalueOf(i)<\/code><\/td><td>20.318.316<\/td><td>20.251.621 \u2013 20.385.011<\/td><\/tr><tr><td><code>String.\u200b\u200bformat(\"%d\", i)<\/code><\/td><td>2.107.397<\/td><td>2.075.553 \u2013 2.139.240<\/td><\/tr><tr><td><code>\"\" + i<\/code><\/td><td>23.358.668<\/td><td>23.178.506 \u2013 23.538.831<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java7.png\"><img decoding=\"async\" width=\"602\" height=\"393\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java7.png\" alt=\"Java 7 int-to-String Performance\" class=\"wp-image-7166\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java7.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java7-224x146.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java7-336x219.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java7-504x329.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java7-400x261.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java7-600x392.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><figcaption class=\"wp-element-caption\"> Java 7 int-to-String Performance <\/figcaption><\/figure>\n<\/div>\n\n\n<p>Die ersten zwei Varianten k\u00f6nnen als gleich schnell angesehen werden, was zu erwarten ist, da <code>String.valueOf(i)<\/code> lediglich <code>Integer.toString(i)<\/code> aufruft und dieser Aufruf durch den HotSpot-Compiler wegoptimiert wird. <\/p>\n\n\n\n<p>Die dritte Variante ist erwartungsgem\u00e4\u00df langsamer, da hier der Format-String geparst werden muss.<\/p>\n\n\n\n<p>Die vierte Variante (<code>\"\" + i<\/code>) ist unter Java 7 deutlich schneller (knapp 15 %) als die ersten zwei Varianten.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Messergebnisse int-to-String mit Java 8<\/h4>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><td><strong>Methode<\/strong><\/td><td><strong>Operationen pro Sekunde<\/strong><\/td><td><strong>Konfidenz\u200bintervall (99,9 %)<\/strong><\/td><\/tr><tr><td><code>Integer.\u200btoString(i)<\/code><\/td><td>20.939.910<\/td><td>20.699.671 \u2013 21.180.149<\/td><\/tr><tr><td><code>String.\u200bvalueOf(i)<\/code><\/td><td>20.920.359<\/td><td>20.737.898 \u2013 21.102.821<\/td><\/tr><tr><td><code>String.\u200bformat(\"%d\", i)<\/code><\/td><td>2.284.027<\/td><td>2.218.004 \u2013 2.350.050<\/td><\/tr><tr><td><code>\"\" + i<\/code><\/td><td>23.777.738<\/td><td>23.651.239 \u2013 23.904.237<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java8.png\"><img decoding=\"async\" width=\"602\" height=\"393\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java8.png\" alt=\"Java 8 int-to-String Performance\" class=\"wp-image-7167\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java8.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java8-224x146.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java8-336x219.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java8-504x329.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java8-400x261.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java8-600x392.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><figcaption class=\"wp-element-caption\">Java 8 int-to-String Performance<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Bei Java 8 zeigt sich ein sehr \u00e4hnliches Ergebnis wie bei Java 7, wobei alle Varianten zwischen 2 % und 8 % an Geschwindigkeit zugelegt haben.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Messergebnisse int-to-String mit Java 9<\/h4>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><td><strong>Methode<\/strong><\/td><td><strong>Operationen pro Sekunde<\/strong><\/td><td><strong>Konfidenz\u200b\u200bintervall (99,9 %)<\/strong><\/td><\/tr><tr><td><code>Integer.\u200btoString(i)<\/code><\/td><td>28.025.700<\/td><td>27.829.430 \u2013 28.221.969<\/td><\/tr><tr><td><code>String.\u200b\u200bvalueOf(i)<\/code><\/td><td>27.732.474<\/td><td>27.646.937 \u2013 27.818.010<\/td><\/tr><tr><td><code>String.\u200b\u200bformat(\"%d\", i)<\/code><\/td><td>2.718.377<\/td><td>2.680.574 \u2013 2.756.179<\/td><\/tr><tr><td><code>\"\" + i<\/code><\/td><td>28.354.690<\/td><td>28.151.883 \u2013 28.557.497<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java9.png\"><img decoding=\"async\" width=\"602\" height=\"413\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java9.png\" alt=\"Java 9 int-to-String Performance\" class=\"wp-image-7168\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java9.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java9-224x154.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java9-336x231.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java9-504x346.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java9-400x274.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java9-600x412.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><figcaption class=\"wp-element-caption\">Java 9 int-to-String Performance<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Bei Java 9 wird es interessant: Alle Varianten haben deutlich (20 bis 30 %) an Durchsatz zugelegt. Allerdings ist der Vorsprung von Variante 4 (<code>\"\" + i<\/code>) auf etwa 2 % zur\u00fcckgefallen. Um Messungenauigkeiten auszuschlie\u00dfen, habe ich den Test mehrfach wiederholt.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Messergebnisse int-to-String mit Java 11<\/h4>\n\n\n\n<p>Java 10 \u00fcberspringe ich. Java 11 ist das aktuelle LTS (Long Term Support) Release. Java 9 war das erste Release nach dem neuen Release-Zyklus und kam dreieinhalb Jahre nach Java 8, daher habe ich es mit aufgenommen.<\/p>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><td><strong>Methode<\/strong><\/td><td><strong>Operationen pro Sekunde<\/strong><\/td><td><strong>Konfidenz\u200bintervall (99,9 %)<\/strong><\/td><\/tr><tr><td><code>Integer.\u200btoString(i)<\/code><\/td><td>27.755.914<\/td><td>27.537.830 \u2013 27.973.998<\/td><\/tr><tr><td><code>String.\u200bvalueOf(i)<\/code><\/td><td>27.836.735<\/td><td>27.676.576 \u2013 27.996.894<\/td><\/tr><tr><td><code>String.\u200bformat(\"%d\", i)<\/code><\/td><td>2.717.551<\/td><td>2.602.165 \u2013 2.832.937<\/td><\/tr><tr><td><code>\"\" + i<\/code><\/td><td>28.237.066<\/td><td>27.965.904 \u2013 28.508.227<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java11.png\"><img decoding=\"async\" width=\"602\" height=\"413\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java11.png\" alt=\"Java 11 int-to-String Performance\" class=\"wp-image-7169\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java11.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java11-224x154.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java11-336x231.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java11-504x346.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java11-400x274.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java11-600x412.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><figcaption class=\"wp-element-caption\">Java 11 int-to-String Performance<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Von Java 9 zu Java 11 gab es keine nennenswerten Ver\u00e4nderungen mehr. Die minimalen Schwankungen f\u00fchre ich auf Messungenauigkeiten zur\u00fcck.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Messergebnisse int-to-String mit Java 13<\/h4>\n\n\n\n<p>Auch Java 12 \u00fcberspringe ich und komme direkt zum aktuellen Release, Java 13.<\/p>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><td><strong>Methode<\/strong><\/td><td><strong>Operationen pro Sekunde<\/strong><\/td><td><strong>Konfidenz\u200bintervall (99,9 %)<\/strong><\/td><\/tr><tr><td><code>Integer.\u200btoString(i)<\/code><\/td><td>27.664.976<\/td><td>27.591.996 \u2013 27.737.955<\/td><\/tr><tr><td><code>String.\u200bvalueOf(i)<\/code><\/td><td>27.718.096<\/td><td>27.646.080 \u2013 27.790.112<\/td><\/tr><tr><td><code>String.\u200bformat(\"%d\", i)<\/code><\/td><td>1.800.345<\/td><td>1.763.017 \u2013 1.837.672<\/td><\/tr><tr><td><code>\"\" + i<\/code><\/td><td>28.293.228<\/td><td>28.156.241 \u2013 28.430.215<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java13.png\"><img decoding=\"async\" width=\"602\" height=\"413\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java13.png\" alt=\"Java 13 int-to-String Performance\" class=\"wp-image-7170\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java13.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java13-224x154.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java13-336x231.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java13-504x346.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java13-400x274.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java13-600x412.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><figcaption class=\"wp-element-caption\">Java 13 int-to-String Performance<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Die Varianten eins, zwei und vier sind quasi unver\u00e4ndert, Variante vier ist nach wie vor der Spitzenreiter. Interessant wird es bei Variante drei (<code>String.format(\"%d\", i)<\/code>): diese ist im Vergleich zu Java 11 knapp 34 % langsamer geworden.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Messergebnisse int-to-String mit Java 14<\/h4>\n\n\n\n<p>Der Vollst\u00e4ndigkeit halber habe ich den Test mit dem letzten Early-Access-Build von Java 14 (ea+19) durchgef\u00fchrt.<\/p>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><td><strong>Methode<\/strong><\/td><td><strong>Operationen pro Sekunde<\/strong><\/td><td><strong>Konfidenz\u200bintervall (99,9 %)<\/strong><\/td><\/tr><tr><td><code>Integer.\u200btoString(i)<\/code><\/td><td>27.642.630<\/td><td>27.484.253 \u2013 27.801.007<\/td><\/tr><tr><td><code>String.\u200bvalueOf(i)<\/code><\/td><td>27.571.938<\/td><td>27.456.427 \u2013 27.687.448<\/td><\/tr><tr><td><code>String.\u200bformat(\"%d\", i)<\/code><\/td><td>1.828.382<\/td><td>1.780.958 \u2013 1.875.807<\/td><\/tr><tr><td><code>\"\" + i<\/code><\/td><td>28.226.175<\/td><td>28.030.308 \u2013 28.422.042<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java14.png\"><img decoding=\"async\" width=\"602\" height=\"413\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java14.png\" alt=\"Java 14 int-to-String Performance\" class=\"wp-image-7171\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java14.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java14-224x154.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java14-336x231.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java14-504x346.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java14-400x274.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-java14-600x412.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><figcaption class=\"wp-element-caption\">Java 14 int-to-String Performance<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Hier sehen wir quasi das gleiche Ergebnis wie bei Java 13. <code>\"\" + i<\/code> ist noch immer der schnellste Weg. Der Vorsprung von etwa 2 % gegen\u00fcber den ersten zwei Varianten hat sich \u00fcber die letzten vier gemessenen Java-Versionen best\u00e4tigt, so dass ich eine Messungenauigkeit ausschlie\u00dfe.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"messergebnis-uebersicht-ueber-alle-java-versionen\">Messergebnis-\u00dcbersicht \u00fcber alle Java Versionen<\/h3>\n\n\n\n<p>Hier seht ihr noch einmal alle Messergebnisse in einem Diagramm zusammengefasst:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions.png\"><img decoding=\"async\" width=\"755\" height=\"393\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions.png\" alt=\"Java int-to-String Performance\" class=\"wp-image-7172\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions.png 755w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions-224x117.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions-336x175.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions-504x262.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions-672x350.png 672w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions-400x208.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/int-to-string-performance-all-java-versions-600x312.png 600w\" sizes=\"(max-width: 755px) 100vw, 755px\" \/><\/a><figcaption class=\"wp-element-caption\">Java int-to-String Performance<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Wir k\u00f6nnen zusammenfassend festhalten \u2013 unabh\u00e4ngig von der Java-Version:<\/p>\n\n\n\n<p class=\"has-text-align-center has-background\" style=\"background-color:#e7edf3\"><code style=\"font-size:150%\">\"\" + i<\/code> <br>ist die schnellste Methode, <br>um ein <code>int<\/code> in einen <code>String<\/code> umzuwandeln.<\/p>\n\n\n\n<p>... wobei der Vorsprung bis Java 8 mit knapp 15 % noch deutlich gr\u00f6\u00dfer war als seit Java 9 mit etwa 2 %.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"erklaerungen-fuer-die-performance-unterschiede\">Erkl\u00e4rungen f\u00fcr die Performance-Unterschiede<\/h2>\n\n\n\n<p>Durch die Messungen sind folgende Fragen aufgekommen, die ich in diesem Abschnitt kl\u00e4ren m\u00f6chte:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Warum haben in Java 9 alle Varianten deutlich an Geschwindigkeit zugelegt?<\/li>\n\n\n\n<li>Warum performt <code>\"\" + i<\/code> durchgehend am besten?<\/li>\n\n\n\n<li>Warum ist <code>String.format(i)<\/code> in Java 13 so viel langsamer geworden?<\/li>\n<\/ul>\n\n\n\n<p>Ich werde dazu den Java-Sourcecode sowie den generierten Bytecode analysieren.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"warum-haben-in-java-9-alle-varianten-deutlich-an-geschwindigkeit-zugelegt\">Warum haben in Java 9 alle Varianten deutlich an Geschwindigkeit zugelegt?<\/h3>\n\n\n\n<p>Meine erste Vermutung war, dass die standardm\u00e4\u00dfig aktivierten \"<a rel=\"noopener\" href=\"https:\/\/openjdk.org:443\/jeps\/254\" target=\"_blank\">Compact Strings<\/a>\" in Java 9 f\u00fcr die gesteigerte Performance verantwortlich sind. Allerdings ergab sich durch das Abschalten dieser (VM-Option \"-XX:-CompactStrings\") keine relevante \u00c4nderung der Geschwindigkeit.<\/p>\n\n\n\n<p>Mein zweiter Ansatz war den Java-Quellcode der <code>Integer.toString(i)<\/code>-Methode von Java 8 und Java 9 zu vergleichen. W\u00e4hrend der Java 9-Code gut verst\u00e4ndlich ist, sieht der Java 8-Code ziemlich kryptisch und optimiert aus. Um zu pr\u00fcfen, ob es an dieser Code-\u00c4nderung liegt (und nicht an JVM-Optimierungen), habe ich den Java 8-Quellcode von <code>Integer<\/code> extrahiert, diesen unter Java 9 in eine Klasse <code>Integer8<\/code> kopiert und mit dieser den Benchmark-Test wiederholt. Und tats\u00e4chlich: Die <code>Integer8.toString(i)<\/code>-Methode war auch unter Java 9 deutlich langsamer, allerdings auch etwas schneller als unter Java 8. Die Hauptursache f\u00fcr den Performancegewinn liegt also in Code-Verbesserungen, und hinzu kommen noch einige JVM-Optimierungen.<\/p>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><td><strong>Methode<\/strong><\/td><td><strong>Operationen pro Sekunde<\/strong><\/td><td><strong>Konfidenz\u200bintervall (99,9 %)<\/strong><\/td><\/tr><tr><td>Java 8-Code unter Java 8<\/td><td>20.939.910<\/td><td>20.699.671 \u2013 21.180.149<\/td><\/tr><tr><td>Java 8-Code unter Java 9<\/td><td>21.737.981<\/td><td>21.517.415 \u2013 21.958.547<\/td><\/tr><tr><td> Java 9-Code unter Java 9<\/td><td>28.025.700<\/td><td>27.829.430 \u2013 28.221.969<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/integer-tostring-java8-vs-java9.png\"><img decoding=\"async\" width=\"602\" height=\"393\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/integer-tostring-java8-vs-java9.png\" alt=\"Performance der Integer.toString()-Methode unter Java 8 und Java 9\" class=\"wp-image-7173\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/integer-tostring-java8-vs-java9.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/integer-tostring-java8-vs-java9-224x146.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/integer-tostring-java8-vs-java9-336x219.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/integer-tostring-java8-vs-java9-504x329.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/integer-tostring-java8-vs-java9-400x261.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/integer-tostring-java8-vs-java9-600x392.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><figcaption class=\"wp-element-caption\">Performance der Integer.toString()-Methode unter Java 8 und Java 9<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Den zugeh\u00f6rigen Quellcode habe ich nicht in meinem GitHub-Repository hinterlegt, da ich mir nicht sicher bin, in wie weit ich Code aus dem JDK, oder auch nur Teile davon, ver\u00f6ffentlichen darf.<\/p>\n\n\n\n<p>Die Varianten drei und vier habe ich an dieser Stelle nicht weiter untersucht. Ich gehe davon aus, dass auch dort die Algorithmen massiv verbessert wurden.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"warum-performt-i-durchgehend-am-besten\">Warum performt <code>\"\" + i<\/code> durchgehend am besten?<\/h3>\n\n\n\n<p>Um zu ermitteln, warum <code>\"\" + i<\/code> am schnellsten ist, schauen wir uns zun\u00e4chst einmal den erzeugten Bytecode an. Das machen wir wie folgt:<\/p>\n\n\n\n<p>Wir erstellen eine Datei <code>IntToStringFast.java<\/code> mit folgendem Inhalt.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">package<\/span> eu.happycoders.int2string;\n\n<span class=\"hljs-keyword\">import<\/span> java.util.Random;\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">IntToStringFast<\/span> <\/span>{\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">main<\/span><span class=\"hljs-params\">(String&#091;] args)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">int<\/span> i = <span class=\"hljs-keyword\">new<\/span> Random().nextInt();\n    System.out.println(<span class=\"hljs-string\">\"\"<\/span> + i);\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Wir kompilieren die Datei wie folgt:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">javac IntToStringFast.java<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Und lassen uns nun wie folgt den Bytecode anzeigen:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">javap -c IntToStringFast.class<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h4 class=\"wp-block-heading\">Variante <code>\"\" + i<\/code> unter Java 7 und Java 8<\/h4>\n\n\n\n<p>Unter Java 7 und Java 8 wird folgender Bytecode erzeugt (hier nur der relevante Auszug):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-number\">14<\/span>: <span class=\"hljs-keyword\">new<\/span>           #<span class=\"hljs-number\">6<\/span>          <span class=\"hljs-comment\">\/\/ class java\/lang\/StringBuilder<\/span>\n<span class=\"hljs-number\">17<\/span>: dup\n<span class=\"hljs-number\">18<\/span>: invokespecial #<span class=\"hljs-number\">7<\/span>          <span class=\"hljs-comment\">\/\/ Method java\/lang\/StringBuilder.\"\":()V<\/span>\n<span class=\"hljs-number\">21<\/span>: ldc           #<span class=\"hljs-number\">8<\/span>          <span class=\"hljs-comment\">\/\/ String<\/span>\n<span class=\"hljs-number\">23<\/span>: invokevirtual #<span class=\"hljs-number\">9<\/span>          <span class=\"hljs-comment\">\/\/ Method java\/lang\/StringBuilder.append:(Ljava\/lang\/String;)Ljava\/lang\/StringBuilder;<\/span>\n<span class=\"hljs-number\">26<\/span>: iload_1\n<span class=\"hljs-number\">27<\/span>: invokevirtual #<span class=\"hljs-number\">10<\/span>         <span class=\"hljs-comment\">\/\/ Method java\/lang\/StringBuilder.append:(I)Ljava\/lang\/StringBuilder;<\/span>\n<span class=\"hljs-number\">30<\/span>: invokevirtual #<span class=\"hljs-number\">11<\/span>         <span class=\"hljs-comment\">\/\/ Method java\/lang\/StringBuilder.toString:()Ljava\/lang\/String;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Dies entspricht folgendem Java-Code (interessanterweise wurde <code>append(\"\")<\/code> nicht wegoptimiert \u2013 das wird hier wohl dem HotSpot-Compiler \u00fcberlassen):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-keyword\">new<\/span> StringBuilder().append(<span class=\"hljs-string\">\"\"<\/span>).append(i).toString();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Um diese Annahme zu best\u00e4tigen, f\u00fchre ich den Benchmark-Test noch einmal mit diesem Code aus und komme zum selben Ergebnis wie f\u00fcr <code>\"\" + i<\/code>.<\/p>\n\n\n\n<p>Wenn wir uns die Methode <code>AbstractStringBuilder.append(int i)<\/code> anschauen, stellen wir fest, dass diese sowohl unter Java 7 als auch unter Java 8 praktisch den gleichen Code enth\u00e4lt wie <code>Integer.toString(int i)<\/code>. Der einzige Unterschied, den ich erkennen konnte, ist dass der <code>StringBuilder<\/code> intern zun\u00e4chst ein <code>char<\/code>-Array der L\u00e4nge 16 anlegt, welches dann in der <code>toString()<\/code>-Methode per <code>System.arraycopy()<\/code> in ein Array der tats\u00e4chlich ben\u00f6tigten L\u00e4nge kopiert wird, w\u00e4hrend <code>Integer.toString()<\/code> von vornherein ein <code>char<\/code>-Array der final ben\u00f6tigten L\u00e4nge erzeugt. Um zu pr\u00fcfen, ob das einen Unterschied ausmacht, erstelle ich einen weiteren Test, in dem ich bei der Erzeugung des StringBuilders als Kapazit\u00e4t 7 mit \u00fcbergebe (im Test werden ausschlie\u00dflich 7-stellige Zufallszahlen erzeugt). Doch auch dies f\u00fchrt wieder zum selben Ergebnis.<\/p>\n\n\n\n<p>Hier ein kurzer Zwischenstand meines aktuellen Tests:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Benchmark                                                        Mode  Cnt         Score   Error  Units\nIntToStringBenchmarkStringBuilder.integerToString               thrpt    2  21168090,044          ops\/s\nIntToStringBenchmarkStringBuilder.stringBuilderCapacity7        thrpt    2  23968649,108          ops\/s\nIntToStringBenchmarkStringBuilder.stringBuilderCapacityDefault  thrpt    2  23769306,792          ops\/s\nIntToStringBenchmarkStringBuilder.stringPlus                    thrpt    2  23989334,180          ops\/s<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Alle <code>StringBuilder<\/code>-Variationen sind nahezu gleich schnell und, nach wie vor, deutlich schneller als <code>Integer.toString()<\/code>. Um der Ursache weiter auf den Grund zu gehen, kopiere ich den Quellcode sowohl von <code>Integer<\/code> als auch von <code>StringBuilder<\/code> und f\u00fchre die Tests damit erneut aus. Ich erhalten folgendes Ergebnis (die Benchmarks mit der \"8\" sind die mit dem kopierten Quellcode):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Klartext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Benchmark                                                  Mode  Cnt         Score   Error  Units\nIntToStringBenchmarkStringBuilderInline.integerToString   thrpt    2  20518228,534          ops\/s\nIntToStringBenchmarkStringBuilderInline.integer8ToString  thrpt    2  19681140,450          ops\/s\nIntToStringBenchmarkStringBuilderInline.stringBuilder     thrpt    2  23873235,183          ops\/s\nIntToStringBenchmarkStringBuilderInline.stringBuilder8    thrpt    2  19990576,858          ops\/s <\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Klartext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Interessant: Im kopierten Quellcode sind <code>Integer.toString(i)<\/code> und <code>\"\" + i<\/code> beinahe gleich schnell \u2013 wie ich es nach Sichtung des Quellcodes eigentlich auch erwartet h\u00e4tte. Beide kopierte Klassen sind jedoch langsamer als die Klassen aus dem JDK. Was kann das bedeuten? <\/p>\n\n\n\n<p>Stimmen die kompilierten Klassen im JDK nicht mit dem mitgelieferten Quellcode \u00fcberein? Um das zu pr\u00fcfen, entferne ich die Datei <code>src.zip<\/code> aus dem JDK-Verzeichnis, so dass IntelliJ beim Klick auf eine Klasse nicht den mitgelieferten Quellcode anzeigt, sondern die Klasse dekompiliert. Die dekompilierte Klasse sieht exakt so aus wie der Quellcode (bis auf dass lokale Variablennamen generisch sind).<\/p>\n\n\n\n<p>An dieser Stelle breche ich die Analyse f\u00fcr Java 7 und Java 8 vorerst ab. Man k\u00f6nnte sich jetzt noch mit den VM-Optionen <code>-XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining<\/code> anzeigen lassen, wie HotSpot den Code im Detail optimiert, doch daf\u00fcr fehlt mir die Zeit.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Variante <code>\"\" + i<\/code> seit Java 9<\/h4>\n\n\n\n<p>Seit Java 9 wird aus <code>\"\" + i<\/code> ein anderer Bytecode erzeugt \u2013 und zwar nur eine einzige Zeile:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"Java\" data-shcb-language-slug=\"java\"><span><code class=\"hljs language-java\"><span class=\"hljs-number\">15<\/span>: invokedynamic #<span class=\"hljs-number\">6<\/span>,  <span class=\"hljs-number\">0<\/span>      <span class=\"hljs-comment\">\/\/ InvokeDynamic #0:makeConcatWithConstants:(I)Ljava\/lang\/String;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">Java<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">java<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Die Methode <code>makeConcatWithConstants()<\/code> \"erm\u00f6glicht die Erstellung von optimierten String-Verkettungsmethoden, die verwendet werden k\u00f6nnen, um eine bekannte Anzahl von Argumenten bekannter Typen effizient zu verketten\" (s. <a rel=\"noopener\" href=\"https:\/\/docs.oracle.com\/javase\/9\/docs\/api\/java\/lang\/invoke\/StringConcatFactory.html#makeConcatWithConstants-java.lang.invoke.MethodHandles.Lookup-java.lang.String-java.lang.invoke.MethodType-java.lang.String-java.lang.Object...-\" target=\"_blank\">StringConcatFactory-JavaDoc<\/a>). Ich habe mir den SourceCode von <code>StringConcatFactory.makeConcatWithConstants()<\/code> angeschaut. Letztendlich ruft diese \u2013 \u00fcber ein MethodHandle \u2013 auch wieder <code>StringBuilder.append(int)<\/code> auf. Von daher ist auch hier nicht ohne weiteres erkennbar, warum diese Variante schneller ist als <code>Integer.toString()<\/code>. Erneut scheinen ausgefeilte HotSpot-Optimierungen am Werk zu sein.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"warum-ist-string-formati-in-java-13-so-langsam-geworden\">Warum ist <code>String.format(i)<\/code> in Java 13 so langsam geworden?<\/h3>\n\n\n\n<p>Die Methode <code>String.format()<\/code> ruft sowohl in Java 11 als auch in Java 13 <code>Formatter().format(format, args).toString()<\/code> auf. Um zu pr\u00fcfen, ob es an der int-zu-String-Umwandlung liegt oder am Formatter generell, f\u00fchre ich einen Test mit dem Format-String \"%s\" durch. Als Parameter \u00fcbergebe ich wieder eine Zufallszahl, die ich schon im \"State\" in einen String umwandle und als solchen an die Test-Methode \u00fcbergebe (ihr findet auch diesen Test im <a rel=\"noopener\" href=\"https:\/\/github.com\/SvenWoltmann\/int-to-string-benchmarks\/blob\/main\/src\/main\/java\/eu\/happycoders\/int2string\/FormatterBenchmark.java\" target=\"_blank\">GitHub-Repository<\/a>).<\/p>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><tbody><tr><td><strong>Java-Version<\/strong><\/td><td><strong>Operationen pro Sekunde<\/strong><\/td><td><strong>Konfidenz\u200bintervall (99,9 %)<\/strong><\/td><\/tr><tr><td>Java 11<\/td><td>2.978.241<\/td><td>2.377.067 \u2013 3.579.416<\/td><\/tr><tr><td>Java 13<\/td><td>1.924.183<\/td><td>1.624.398 \u2013 2.223.968<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/string-format-java11-vs-java13-1.png\"><img decoding=\"async\" width=\"602\" height=\"393\" src=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/string-format-java11-vs-java13-1.png\" alt=\"Performance der String.format()-Methode unter Java 11 und Java 13\" class=\"wp-image-7174\" srcset=\"https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/string-format-java11-vs-java13-1.png 602w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/string-format-java11-vs-java13-1-224x146.png 224w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/string-format-java11-vs-java13-1-336x219.png 336w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/string-format-java11-vs-java13-1-504x329.png 504w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/string-format-java11-vs-java13-1-400x261.png 400w, https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/string-format-java11-vs-java13-1-600x392.png 600w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><figcaption class=\"wp-element-caption\">Performance der String.format()-Methode unter Java 11 und Java 13<\/figcaption><\/figure>\n<\/div>\n\n\n<p>Der Formatter ist also generell deutlich langsamer geworden, nicht nur bei der Umwandlung von Integern zu Strings. Um dies tiefergehend zu analysieren fehlt mir aber an dieser Stelle die Zeit. Dieser Artikel ist schon deutlich umfangreicher geworden als urspr\u00fcnglich geplant.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"zusammenfassung-und-ausblick\">Zusammenfassung und Ausblick<\/h2>\n\n\n\n<p>Ausf\u00fchrliche Benchmark-Tests haben gezeigt, dass \u00fcber alle Java-Versionen hinweg <code>\"\" + i<\/code> der schnellste Weg ist, um ein Integer in einen String umzuwandeln. Lag der Vorsprung bei Java 7 und Java 8 noch bei  beeindruckenden 15 %, ist er seit Java 9 auf etwa 2 % zur\u00fcckgegangen, so dass es heute im Grunde genommen Geschmacksache ist, welche Variante ihr verwendet. <\/p>\n\n\n\n<p>Leider ist es mir nicht gelungen den Grund daf\u00fcr herauszufinden. Kennst du die Ursache? Oder kennst du noch andere performante Wege, um ints in Strings zu konvertieren? Dann freue ich mich \u00fcber deinen Kommentar!<\/p>\n\n\n\n<p>Im <a href=\"\/de\/java\/string-in-int-umwandeln-besonderheiten-fallstricke\/\">n\u00e4chsten Artikel<\/a> zeige ich euch, was in der entgegengesetzten Richtung, also beim Parsen von Strings in ints zu beachten ist.<\/p>\n<aside><p>Wenn dir der Artikel weitergeholfen hat, w\u00fcrde ich mich sehr \u00fcber eine positive Bewertung auf meinem <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">ProvenExpert-Profil<\/a> freuen. Dein Feedback hilft mir, meine Inhalte weiter zu verbessern und motiviert mich, neue informative Artikel zu schreiben.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"https:\/\/www.provenexpert.com\/de-de\/sven-woltmann-happycoders-eu\/7smk\/\" target=\"_blank\" rel=\"noopener\">Bewertung abgeben<\/a><\/p>\r\n                        <p>Du m\u00f6chtest \u00fcber alle neue Java-Features auf dem Laufenden sein? Dann <a href=\"#\" data-formkit-toggle=\"d8ee997126\">klicke hier<\/a>, um dich f\u00fcr den HappyCoders-Newsletter anzumelden.<\/p>\r\n                        <p>\ud83d\udc49 <a href=\"#\" data-formkit-toggle=\"d8ee997126\">Newsletter-Anmeldung<\/a><\/p><\/aside>","protected":false},"excerpt":{"rendered":"<p>In diesem Artikel zeige ich dir, was in Java die schnellste Methode ist, um ein int in einen String umzuwandeln. Du wirst \u00fcberrascht sein!<\/p>\n","protected":false},"author":1,"featured_media":34490,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_titles_title":"","_seopress_titles_desc":"Was ist der schnellste Weg in Java ein int in einen String zu konvertieren? Ich zeige dir vier Methoden und Benchmark-Tests f\u00fcr Java 7\u201314.","_seopress_robots_index":"","_seopress_robots_follow":"","_seopress_robots_imageindex":"","_seopress_robots_snippet":"","_seopress_robots_primary_cat":"none","_seopress_robots_breadcrumbs":"","_seopress_robots_freeze_modified_date":"","_seopress_robots_custom_modified_date":"","_seopress_robots_canonical":"","_seopress_social_fb_title":"","_seopress_social_fb_desc":"","_seopress_social_fb_img":"","_seopress_social_fb_img_attachment_id":0,"_seopress_social_fb_img_width":0,"_seopress_social_fb_img_height":0,"_seopress_social_twitter_title":"","_seopress_social_twitter_desc":"","_seopress_social_twitter_img":"","_seopress_social_twitter_img_attachment_id":0,"_seopress_social_twitter_img_width":0,"_seopress_social_twitter_img_height":0,"_seopress_redirections_value":"","_seopress_redirections_enabled":"","_seopress_redirections_enabled_regex":"","_seopress_redirections_logged_status":"both","_seopress_redirections_param":"","_seopress_redirections_type":301,"_seopress_analysis_target_kw":"int in string,int zu string,int nach string,integer zu string,int-to-string","_seopress_news_disabled":"","_seopress_video_disabled":"","_seopress_video":[{"url":"","title":"","desc":"","thumbnail":"","duration":"","rating":"","view_count":"","tag":"","cat":""}],"_seopress_pro_schemas_manual":[{"_seopress_pro_rich_snippets_type":"none"}],"_seopress_pro_rich_snippets_disable_all":"","_seopress_pro_rich_snippets_disable":[],"_seopress_pro_schemas":[],"_uag_custom_page_level_css":"","_wp_convertkit_post_meta":{"form":"-1","landing_page":"","tag":"0","restrict_content":"0"},"_metis_text_type":"standard","_metis_text_length":17648,"_post_count":0,"footnotes":""},"categories":[64],"tags":[157],"class_list":["post-6781","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-java-performance-de"],"uagb_featured_image_src":{"full":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string.jpg",1770,986,false],"thumbnail":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string.jpg",150,84,false],"medium":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string.jpg",300,167,false],"medium_large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string.jpg",768,428,false],"large":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string.jpg",1024,570,false],"feature_thumb_224":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-224x125.jpg",224,125,true],"feature_thumb_336":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-336x187.jpg",336,187,true],"feature_thumb_504":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-504x281.jpg",504,281,true],"feature_thumb_672":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-672x374.jpg",672,374,true],"half_400":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-400x223.jpg",400,223,true],"half_600":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-600x334.jpg",600,334,true],"full_800":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-800x446.jpg",800,446,true],"full_944":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-944x526.jpg",944,526,true],"full_1200":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-1200x668.jpg",1200,668,true],"wide_1180":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-1180x490.jpg",1180,490,true],"wide_1770":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string-1770x735.jpg",1770,735,true],"1536x1536":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string.jpg",1536,856,false],"2048x2048":["https:\/\/www.happycoders.eu\/wp-content\/uploads\/2019\/10\/java-int-to-string.jpg",1770,986,false]},"uagb_author_info":{"display_name":"Sven Woltmann","author_link":"https:\/\/www.happycoders.eu\/de\/author\/sven\/"},"uagb_comment_info":0,"uagb_excerpt":"In diesem Artikel zeige ich dir, was in Java die schnellste Methode ist, um ein int in einen String umzuwandeln. Du wirst \u00fcberrascht sein!","public_identification_id":"499fee99b926484d93d9b8ea8d817377","private_identification_id":"92b7d17e399e4764bd56ba536ab30364","_links":{"self":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/6781","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/comments?post=6781"}],"version-history":[{"count":10,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/6781\/revisions"}],"predecessor-version":[{"id":42177,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/posts\/6781\/revisions\/42177"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media\/34490"}],"wp:attachment":[{"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/media?parent=6781"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/categories?post=6781"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.happycoders.eu\/de\/wp-json\/wp\/v2\/tags?post=6781"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}