{"id":3716,"date":"2017-02-24T23:43:41","date_gmt":"2017-02-24T21:43:41","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=3716"},"modified":"2017-02-25T02:16:16","modified_gmt":"2017-02-25T00:16:16","slug":"statische-ofxxx-methoden-zum-aufbau-unveraenderbaren-set-list-map-datenstrukturen","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2017\/02\/statische-ofxxx-methoden-zum-aufbau-unveraenderbaren-set-list-map-datenstrukturen\/","title":{"rendered":"Statische ofXXX(\u2026)-Methoden zum Aufbau unver\u00e4nderbarer Set-, List-, Map-Datenstrukturen"},"content":{"rendered":"<p>In Java 9 sind echte immutable Datenstrukturen dazugekommen, die sich \u00fcber statische ofXXX(\u2026)-Methoden der Schnittstellen List, Set und Map aufbauen lassen. Jede versuchte \u00c4nderung an den Datenstrukturen f\u00fchrt zu einer UnsupportedOperationException. Damit eigenen sie sich hervorragend f\u00fcr konstante Sammlungen, die problemlos herumgereicht k\u00f6nnen.<\/p>\n<p>Aus Performance-Gr\u00fcnden sind die of(\u2026)-Methoden \u00fcberladen, das \u00e4ndert aber nichts an ihrem Aufrufvarianten. null-Elemente sind grunds\u00e4tzlich verboten und f\u00fchren zu einer NullPointerException.<\/p>\n<p>interface\u00a0java.util.List&lt;E&gt;<br \/>\nextends\u00a0Collection&lt;E&gt;<\/p>\n<ul>\n<li>static &lt;E&gt; List&lt;E&gt; of(E&#8230; elements)<br \/>\nErzeugt eine neue immutable Liste aus den Elementen. Vor dem praktischen of(\u2026) wurden Listen in der Regel mit Array.asList(\u2026) aufgebaut. Doch die sind nicht immutable und schreiben auf das Feld durch.<\/li>\n<\/ul>\n<p>interface\u00a0java.util.Set&lt;E&gt;<br \/>\nextends\u00a0Collection&lt;E&gt;<\/p>\n<ul>\n<li>static &lt;E&gt; Set&lt;E&gt; of(E&#8230; elements)<br \/>\nErzeugt eine Menge aus den gegebenen Elementen. Doppelte Eintr\u00e4ge sind verboten und f\u00fchren zu einer IllegalArgumentException. Der Versuch, schon vorhandene Elemente in eine \u201enormale\u201c HashSet oder TreeSet hinzuzuf\u00fcgen, ist aber v\u00f6llig legitim. Wie die Implementierung der Menge genau ist, ist verborgen.<\/li>\n<\/ul>\n<p>Beispiel<\/p>\n<p>Zeige an, welche Superhelden in einem String Liste vorkommen:<\/p>\n<p>Set&lt;String&gt; heros = <strong>Set.of( &#8222;Batman&#8220;, &#8222;Spider-Man&#8220;, &#8222;Hellboy&#8220; )<\/strong>;<\/p>\n<p>new Scanner( &#8222;Batman trifft auf Superman&#8220; )<\/p>\n<p>.tokens().filter( heros::contains )<\/p>\n<p>.forEach( System.out::println );\u00a0\u00a0 \u00a0\/\/ Batman<\/p>\n<p>&nbsp;<\/p>\n<p>Zum Aufbau von Assoziationsspeichern gibt es zwei Varianten. Einmal \u00fcber die of(\u2026)-Methode, die Schl\u00fcssel und Wert einfach hintereinander aufnimmt und einmal mit ofEntries(\u2026) \u00fcber ein Vararg von Entry-Objekten. Eine neue statische Methode hilft, diese einfach aufzubauen:<\/p>\n<p>interface\u00a0java.util.Map&lt;K,V&gt;<\/p>\n<ul>\n<li>static &lt;K, V&gt; Map&lt;K, V&gt; of() {<\/li>\n<li>static &lt;K, V&gt; Map&lt;K, V&gt; of(K k1, V v1)<\/li>\n<li>static &lt;K, V&gt; Map&lt;K, V&gt; of(K k1, V v1 \u2026 )<\/li>\n<li>static &lt;K, V&gt; Map&lt;K, V&gt; of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10)<\/li>\n<li>static &lt;K, V&gt; Map&lt;K, V&gt; ofEntries(Entry&lt;? extends K, ? extends V&gt;&#8230; entries)<\/li>\n<li>static &lt;K, V&gt; Entry&lt;K, V&gt; entry(K k, V v)<\/li>\n<\/ul>\n<p>Beispiel<\/p>\n<p>Baue eine Map mit Java-Versionen und deren Erscheinungsdaten auf und gib sie aus:<\/p>\n<p>Map&lt;String, LocalDate&gt; map =<\/p>\n<p><strong>Map.ofEntries<\/strong>( <strong>Map.entry<\/strong>( &#8222;JDK 1.0&#8220;, LocalDate.of( 1996, Month.JANUARY, 23 ) ),<\/p>\n<p><strong>Map.entry<\/strong>( &#8222;JDK 1.1&#8220;, LocalDate.of( 1997, Month.FEBRUARY, 19 ) ) );<\/p>\n<p>map.forEach( (k, v) -&gt; System.out.println( k + &#8222;=&#8220; + v ) );<\/p>\n<h4>Best-Practise und Weise Worte<\/h4>\n<p>Die neuen ofXXX(\u2026)-Methoden sind eine Bereicherung, aber auch mit Vorsicht einzusetzen \u2013 die alten API-Methoden werden dadurch nicht langweilig:<\/p>\n<ul>\n<li>Da die of(\u2026)-Methoden \u00fcberladen sind l\u00e4sst sich prinzipiell auch emptyXXX() durch of() und Collections.singleon() durch of(element) ersetzen \u2013 allerdings sagen die Collections-Methodennamen gut aus, was hier passiert und sind vielleicht expliziter.<\/li>\n<li>Auf einem existierenen Array hat Arrays.asList(\u2026) zwar den Nachteil, dass die Array-Elemente ausgetauscht werden k\u00f6nnen, allerdings ist der Speicherbedarf minimal, da der Adapter asList(\u2026) keine Kopie anlegt, wohingegen List.of(\u2026) zum Aufbau einer neuen internen Datenstruktur f\u00fchrt, die Speicher kostet.<\/li>\n<li>Falls null-Eintr\u00e4ge in der Sammlung sein sollen, d\u00fcrfen keine ofXXX(\u2026)-Methoden verwendet werden.<\/li>\n<li>Beim Refactoring k\u00f6nnten Entwickler geneigt sein, existierenden Code mit den Collections-Methode durch die ofXXX(\u2026)-Methoden zu ersetzen. Das kann zum Problem mit serialisierten Daten werden, denn das Serialisierungsformat ist ein anders.<\/li>\n<li>Bei Set und Map wird ein k\u00fcnstlicher SALT eingesetzt, der die Reihenfolge der Elemente bei jedem JVM-Start immer \u00e4ndert. Das hei\u00dft, der Iterator von of(&#8222;a&#8220;, &#8222;b&#8220;, &#8222;c&#8220;) kann einmal \u201ea\u201c, \u201eb\u201c, \u201ec\u201c liefern, dann beim n\u00e4chsten Programmstart \u201eb\u201c, \u201ec\u201c, \u201ea\u201c.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Java 9 sind echte immutable Datenstrukturen dazugekommen, die sich \u00fcber statische ofXXX(\u2026)-Methoden der Schnittstellen List, Set und Map aufbauen lassen. Jede versuchte \u00c4nderung an den Datenstrukturen f\u00fchrt zu einer UnsupportedOperationException. Damit eigenen sie sich hervorragend f\u00fcr konstante Sammlungen, die problemlos herumgereicht k\u00f6nnen. Aus Performance-Gr\u00fcnden sind die of(\u2026)-Methoden \u00fcberladen, das \u00e4ndert aber nichts an ihrem [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[11,85],"tags":[],"class_list":["post-3716","post","type-post","status-publish","format-standard","hentry","category-insel","category-java-9"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3716","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/comments?post=3716"}],"version-history":[{"count":2,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3716\/revisions"}],"predecessor-version":[{"id":3750,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3716\/revisions\/3750"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=3716"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=3716"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=3716"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}