{"id":3955,"date":"2017-08-10T16:35:04","date_gmt":"2017-08-10T14:35:04","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=3955"},"modified":"2017-08-10T16:35:04","modified_gmt":"2017-08-10T14:35:04","slug":"konstruktorreferenzen","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2017\/08\/konstruktorreferenzen\/","title":{"rendered":"Konstruktorreferenzen"},"content":{"rendered":"<p>Um ein Objekt aufzubauen, nutzen wir das Schl\u00fcsselwort new. Das f\u00fchrt zum Aufruf eines Konstruktors, dem sich optional Argumente \u00fcbergeben lassen. Die Java-API deklariert aber auch Typen, von denen sich keine direkten Exemplare mit new aufbauen lassen. Stattdessen gibt es Erzeuger, deren Aufgabe es ist, Objekte aufzubauen. Die Erzeuger k\u00f6nnen statische oder auch nichtstatische Methoden sein:<\/p>\n<table>\n<tbody>\n<tr>\n<td width=\"188\">Konstruktor \u2026<\/td>\n<td width=\"108\">\u2026 erzeugt:<\/td>\n<td width=\"228\">Erzeuger \u2026<\/td>\n<td width=\"108\">\u2026 baut:<\/td>\n<\/tr>\n<tr>\n<td width=\"188\">new Integer( &#8222;1&#8220; )<\/td>\n<td width=\"108\">Integer<\/td>\n<td width=\"228\">Integer.valueOf( &#8222;1&#8220; )<\/td>\n<td width=\"108\">Integer<\/td>\n<\/tr>\n<tr>\n<td width=\"188\">new File( &#8222;dir&#8220; )<\/td>\n<td width=\"108\">File<\/td>\n<td width=\"228\">Paths.get( &#8222;dir&#8220; )<\/td>\n<td width=\"108\">Path<\/td>\n<\/tr>\n<tr>\n<td width=\"188\">new BigInteger( val )<\/td>\n<td width=\"108\">BigInteger<\/td>\n<td width=\"228\">BigInteger.valueOf( val )<\/td>\n<td width=\"108\">BigInteger<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Tabelle 1.4: Beispiele f\u00fcr Konstruktoren und Erzeuger-Methoden<\/p>\n<p>Beide, Konstruktoren und Erzeuger, lassen sich als spezielle Funktionen sehen, die von einem Typ in einen anderen Typ konvertieren. Damit eignen sie sich perfekt f\u00fcr Transformationen, und in einem Beispiel haben wir das schon eingesetzt:<\/p>\n<pre>Arrays.stream(\u00a0words\u00a0)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.\u00a0\u2026\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.map(\u00a0Integer::parseInt\u00a0)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.\u00a0\u2026<\/pre>\n<p>Integer.parseInt(string) ist eine Methode, die sich einfach mit einer Methodenreferenz fassen l\u00e4sst, und zwar als Integer::parseInt. Aber was ist mit Konstruktoren? Auch sie transformieren! Statt Integer.parseInt(string) h\u00e4tte ja auch new Integer(string) eingesetzt werden k\u00f6nnen.<\/p>\n<p>Wo Methodenreferenzen statische Methoden und Objektmethoden angeben k\u00f6nnen, bieten Konstruktorreferenzen die M\u00f6glichkeit, Konstruktoren anzugeben, sodass diese als Erzeuger an anderer Stelle \u00fcbergeben werden k\u00f6nnen. Damit lassen sich elegant Konstruktoren als Erzeuger angeben, und zwar auch von einer Klasse, die nicht \u00fcber Erzeugermethoden verf\u00fcgt. Wie auch bei Methodenreferenzen spielt eine funktionale Schnittstelle eine entscheidende Rolle, doch dieses Mal ist es die Methode der funktionalen Schnittstelle, die mit ihrem Aufruf zum Konstruktoraufruf f\u00fchrt. Wo syntaktisch bei Methodenreferenzen rechts vom Doppelpunkt ein Methodenname steht, ist dies bei Konstruktorreferenzen ein new.<a href=\"#_ftn1\" name=\"_ftnref1\">[1]<\/a> Also ergibt sich alternativ zu<\/p>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.map(\u00a0Integer::parseInt\u00a0)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\u00a0Methode\u00a0Integer.parseInt(String)<\/pre>\n<p>in unserem Beispiel das Ergebnis mittels:<\/p>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.map(\u00a0Integer::new\u00a0)\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\u00a0Konstruktor\u00a0Integer(String)<\/pre>\n<p>Mit der Konstruktorreferenz gibt es vier M\u00f6glichkeiten, funktionale Schnittstellen zu implementieren; die drei verbleibenden Varianten sind Lambda-Ausdr\u00fccke, Methodenreferenzen und klassische Implementierung \u00fcber eine Klasse.<\/p>\n<p><strong>Beispiel:\u00a0<\/strong>Die funktionale Schnittstelle sei:<\/p>\n<pre>interface\u00a0DateFactory\u00a0{\u00a0Date\u00a0create();\u00a0}<\/pre>\n<p>Die folgende Konstruktorreferenz bindet den Konstruktor an die Methode create() der funktionalen Schnittstelle:<\/p>\n<pre>DateFactory\u00a0factory\u00a0=\u00a0Date::new;\r\n System.out.print(\u00a0factory.create()\u00a0);\u00a0\/\/\u00a0zum\u00a0Beispiel\u00a0Sat\u00a0Dec\u00a029\u00a009:56:35\u00a0CET\u00a02012<\/pre>\n<p>Beziehungsweise die letzten beiden Zeilen zusammengefasst:<\/p>\n<p>System.out.println(\u00a0((DateFactory)Date::new).create()\u00a0);<\/p>\n<p>Soll nur der Standard-Konstruktor aufgerufen werden, muss die funktionale Schnittstelle nur eine Methode besitzen, die keinen Parameter besitzt und etwas zur\u00fcckliefert. Der R\u00fcckgabetyp der Methode muss nat\u00fcrlich mit dem Klassentyp zusammenpassen. Das gilt f\u00fcr den Typ DateFactory aus unserem Beispiel. Doch es geht noch etwas generischer, zum Beispiel mit der vorhandenen funktionalen Schnittstelle Supplier, wie wir gleich sehen werden.<\/p>\n<p>In der API finden sich oftmals Parameter vom Typ Class, die als Typangabe dazu verwendet werden, dass \u00fcber den Constructor der Class mit der Methode newInstance() Exemplare gebilder werden. Der Einsatz von Class l\u00e4sst sich durch eine funktionale Schnittstelle ersetzen, und Konstruktorreferenzen lassen sich an Stelle von Class-Objekten \u00fcbergeben.<\/p>\n<h3>Standard- und parametrisierte Konstruktoren<\/h3>\n<p>Beim Standard-Konstruktor hat die Methode nur eine R\u00fcckgabe, bei einem parametrisierten Konstruktor muss die Methode der funktionalen Schnittstelle nat\u00fcrlich \u00fcber eine kompatible Parameterliste verf\u00fcgen:<\/p>\n<table>\n<tbody>\n<tr>\n<td width=\"212\"><strong>Konstruktor<\/strong><\/td>\n<td width=\"212\">Date()<\/td>\n<td width=\"212\">Date(long t)<\/td>\n<\/tr>\n<tr>\n<td width=\"212\"><strong>Kompatible<\/strong> <strong>funktionale<\/strong> <strong>Schnittstelle<\/strong><\/td>\n<td width=\"212\">interface DateFactory {<br \/>\nDate create();<br \/>\n}<\/td>\n<td width=\"212\">interface DateFactory {<br \/>\nDate create(long t);<br \/>\n}<\/td>\n<\/tr>\n<tr>\n<td width=\"212\"><strong>Konstruktorreferenz<\/strong><\/td>\n<td width=\"212\">DateFactory factory =<br \/>\nDate::new;<\/td>\n<td width=\"212\">DateFactory factory =<br \/>\nDate::new;<\/td>\n<\/tr>\n<tr>\n<td width=\"212\"><strong>Aufruf<\/strong><\/td>\n<td width=\"212\">factory.create();<\/td>\n<td width=\"212\">factory.create(1);<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Tabelle 1.5: Standard- und parametrisierter Konstruktor mit korrespondierenden funktionalen Schnittstellen<\/p>\n<p><strong>Hinweis:\u00a0<\/strong>Kommt die Typ-Inferenz des Compilers an ihre Grenzen, sind zus\u00e4tzliche Typinformationen gefordert. In diesem Fall werden hinter dem Doppelpunkt in eckigen Klammen weitere Angaben gemacht, etwa Klasse::&lt;Typ1, Typ2&gt;new.<\/p>\n<h3>N\u00fctzliche vordefinierte Schnittstellen f\u00fcr Konstruktorreferenzen<\/h3>\n<p>Die f\u00fcr einen Standard-Konstruktor passende funktionale Schnittstelle muss eine R\u00fcckgabe besitzen und keinen Parameter annehmen; die funktionale Schnittstelle f\u00fcr einen parametrisierten Konstruktor muss eine entsprechende Parameterliste haben. Es kommt nun h\u00e4ufig vor, dass der Konstruktor ein Standard-Konstruktor ist oder genau einen Parameter annimmt. Hier ist es vorteilhaft, dass f\u00fcr diese beiden F\u00e4lle die Java-API zwei praktische (generisch deklarierte) funktionale Schnittstellen mitbringt:<\/p>\n<table>\n<tbody>\n<tr>\n<td width=\"158\">Funktionale<br \/>\nSchnittstelle<\/td>\n<td width=\"158\">Funktions-<br \/>\nDeskriptor<\/td>\n<td width=\"115\">Abbildung<\/td>\n<td width=\"310\">Passt auf<\/td>\n<\/tr>\n<tr>\n<td width=\"158\">Supplier&lt;T&gt;<\/td>\n<td width=\"158\">T get()<\/td>\n<td width=\"115\">() \u2192 T<\/td>\n<td width=\"310\">Standard-Konstruktor<\/td>\n<\/tr>\n<tr>\n<td width=\"158\">Function&lt;T,R&gt;<\/td>\n<td width=\"158\">R apply(T t)<\/td>\n<td width=\"115\">(T) \u2192 R<\/td>\n<td width=\"310\">einfacher parametrisierter Konstruktor<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Tabelle 1.6: Vorhandene funktionale Schnittstellen als Erzeuger<\/p>\n<p><strong>Beispiel:<\/strong> Die funktionale Schnittstelle Supplier&lt;T&gt; hat eine T get()-Methode, die wir mit dem Standard-Konstruktor von Date verbinden k\u00f6nnen:<\/p>\n<pre>Supplier&lt;Date&gt;\u00a0factory\u00a0=\u00a0Date::new;\r\n System.out.print(\u00a0factory.get()\u00a0);<\/pre>\n<p>Wir nutzen Supplier mit dem Typparameter Date, was den parametrisierten Typ Supplier&lt;Date&gt; ergibt, und get() liefert folglich den Typ Date. Der Aufruf factory.get() f\u00fchrt zum Aufruf des Konstruktors.<\/p>\n<h4>Ausblick *<\/h4>\n<p>Besonders interessant werden die Konstruktorreferenzen mit den neuen Bibliotheksmethoden der Stream-API. Nehmen wir eine Liste vom Typ Zeitstempel an. Der Konstruktor Date(long) nimmt einen solchen Zeitstempel entgegen, und mit einem Date-Objekt k\u00f6nnen wir Vergleiche vornehmen, etwa ob ein Datum hinter einem anderen Datum liegt. Folgendes Beispiel listet alle Datumswerte auf, die nach dem 1.1.2012 liegen:<\/p>\n<pre>Long[]\u00a0timestamps\u00a0=\u00a0{\u00a02432558632L,\u00a01455872986345L\u00a0};\r\n Date\u00a0thisYear\u00a0=\u00a0new\u00a0GregorianCalendar(\u00a02012,\u00a0Calendar.JANUARY,\u00a01\u00a0).getTime();\r\n Arrays.stream(\u00a0timestamps\u00a0)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.map(\u00a0Date::new\u00a0)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.filter(\u00a0thisYear::before\u00a0)\r\n \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.forEach(\u00a0System.out::println\u00a0);\u00a0\u00a0\/\/\u00a0Fri\u00a0Feb\u00a019\u00a010:09:46\u00a0CET\u00a02016<\/pre>\n<p>Die Konstruktorreferenz Date::new hilft dabei, das long mit dem Zeitstempel in ein Date-Objekt zu konvertieren.<\/p>\n<p><strong>Denksportaufgabe<\/strong>: Ein Konstruktor kann als Supplier oder Function gelten. Problematisch sind mal wieder gepr\u00fcfte Ausnahmen. Der Leser soll \u00fcberlegen, ob der Konstruktor URI(String str) throws URISyntaxException \u00fcber URI::new angesprochen werden kann.<\/p>\n<p><a href=\"#_ftnref1\" name=\"_ftn1\"><sup>[1]<\/sup><\/a> Da new ein Schl\u00fcsselwort ist, kann keine Methode so hei\u00dfen; der Identifizierer ist also sicher.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Um ein Objekt aufzubauen, nutzen wir das Schl\u00fcsselwort new. Das f\u00fchrt zum Aufruf eines Konstruktors, dem sich optional Argumente \u00fcbergeben lassen. Die Java-API deklariert aber auch Typen, von denen sich keine direkten Exemplare mit new aufbauen lassen. Stattdessen gibt es Erzeuger, deren Aufgabe es ist, Objekte aufzubauen. Die Erzeuger k\u00f6nnen statische oder auch nichtstatische Methoden [&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":[66],"tags":[],"class_list":["post-3955","post","type-post","status-publish","format-standard","hentry","category-java-8"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3955","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=3955"}],"version-history":[{"count":1,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3955\/revisions"}],"predecessor-version":[{"id":3956,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/3955\/revisions\/3956"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=3955"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=3955"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=3955"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}