{"id":2742,"date":"2014-03-23T12:02:56","date_gmt":"2014-03-23T10:02:56","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=2742"},"modified":"2014-03-23T12:03:07","modified_gmt":"2014-03-23T10:03:07","slug":"methoden-referenz-von-java-8","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2014\/03\/methoden-referenz-von-java-8\/","title":{"rendered":"Methoden-Referenz von Java 8"},"content":{"rendered":"<p>Je gr\u00f6\u00dfer Software-Systeme werden, desto wichtiger werden Dinge wie Klarheit, Wiederverwendbarkeit und Dokumentation. Wir haben f\u00fcr unseren String-Comparator eine Implementierung geschrieben, anfangs \u00fcber eine innere Klasse, sp\u00e4ter \u00fcber einen Lambda-Ausdruck. In jedem Fall haben wir Code geschrieben. Doch was w\u00e4re, wenn eine Utility-Klasse schon eine Implementierung mitbringen w\u00fcrde? Dann k\u00f6nnte der Lambda-Ausdruck nat\u00fcrlich an die vorhandene Implementierung delegieren, und wir sparen Code. Schauen wir uns das mal an einem Beispiel an:<\/p>\n<pre>class StringUtils {\r\n\u00a0 public static <b>int compareTrimmed( String s1, String s2 )<\/b> {\r\n\u00a0\u00a0\u00a0 return s1.trim().compareTo( s2.trim() );\r\n\u00a0 }\u00a0\u00a0\u00a0\u00a0\r\n}\r\n\r\n<span style=\"font-size: 14px;\">public class CompareIgnoreCase {\r\n<\/span>\u00a0 public static void main( String[] args ) {\r\n\u00a0\u00a0\u00a0 String[] words = { \"A\", \"B\", \"a\" };\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 Arrays.sort( words, <b>(String s1, String s2) -&gt; \r\nStringUtils.compareTrimmed(s1, s2)<\/b> );\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 System.out.println( Arrays.toString( words ) );\r\n\u00a0 }\r\n}<\/pre>\n<p>Auff\u00e4llig ist hier, dass die referenzierte Methode compareTrimmed(String,String) von den Parametertypen und vom R\u00fcckgabetyp genau auf die compare(\u2026)-Methode eines Comparator passt. F\u00fcr genau solche F\u00e4lle gibt es eine weitere syntaktische Verk\u00fcrzung, so dass im Code kein Lambda-Ausdruck, sondern nur noch ein Methodenverweis notwendig ist.<\/p>\n<p>Definition:\u00a0Eine Methoden-Referenz\u00a0ist\u00a0 ein Verweis auf\u00a0 eine Methode ohne diese jedoch aufzurufen. Syntaktisch trennen zwei Doppelpunkte den Klassenamen bzw. die Referenz auf der linken Seite von dem Methodennamen auf der rechten.<\/p>\n<p>Die Zeile<\/p>\n<pre>Arrays.sort( words, <b>(String s1, String s2) -&gt; StringUtils.compareTrimmed(s1, s2)<\/b> );<\/pre>\n<p>l\u00e4sst sich mit einer Methoden-Referenzen abk\u00fcrzen zu:<\/p>\n<pre>Arrays.sort( words, <b>StringUtils::compareTrimmed<\/b> );<\/pre>\n<p>Die Sortiermethode erwartet vom Comparator eine Methode, die zwei Strings annimmt und eine Ganzzahl zur\u00fcckgibt. Der Name der Klasse und der Name der Methode sind unerheblich, weshalb an dieser Stelle eine Methoden-Referenz eingesetzt werden kann.<\/p>\n<p>Eine Methoden-Referenz ist wie ein Lambda-Ausdruck ein Exemplar einer funktionalen Schnittstelle, jedoch f\u00fcr eine existierende Methode einer bekannten Klasse. Wie \u00fcblich bestimmt der Kontext von welchem Typ genau der Ausdruck ist.<\/p>\n<p>Hinweis:\u00a0Gleicher Code f\u00fcr eine Methoden-Referenz kann zu komplett unterschiedlichen Typen f\u00fchren \u2013 der Kontext macht den Unterschied:<\/p>\n<pre>Comparator&lt;String&gt;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 c1 = <b>StringUtils::compareTrimmed<\/b>;\r\nBiFunction&lt;String, String, Integer&gt; c2 = <b>StringUtils::compareTrimmed<\/b>;<\/pre>\n<h4>Varianten von Methoden-Referenzen<\/h4>\n<p>Im Beispiel ist die Methode compareTrimmed(\u2026) statisch, und links vom Doppelpunkt steht der Name eines Typs. Allerdings kann beim Einsatz eines Typnamen die Methode auch nicht-statisch sein, String::length ist so ein Beispiel. Das w\u00e4re eine Funktion, die ein String auf ein int abbildet, in Code: Function&lt;String, Integer&gt; len = String::length;.<\/p>\n<p><span style=\"line-height: 1.5;\">Links von den zwei Doppelpunkten kann auch eine Referenz stehen, was dann immer eine Objektmethode referenziert.<\/span><\/p>\n<p>Beispiel:\u00a0W\u00e4hrend String::length eine Funktion ist, w\u00e4re string::length ein Supplier, unter der Annahme, das string eine Referenzvariable ist:<\/p>\n<pre>String string = \"Goll\";\r\nSupplier&lt;Integer&gt; len = <b>string::length<\/b>;\r\nSystem.out.println( len.get() );\u00a0\u00a0\u00a0\u00a0 \/\/ 4<\/pre>\n<p>System.out ist eine Referenz und eine Methode wie println(\u2026) kann an einen Consumer gebunden werden. Es ist aber auch ein Runnable, weil es println() auch ohne Parameterliste gibt.<\/p>\n<pre>Consumer&lt;String&gt; out = <b>System.out::println<\/b>;\r\nout.accept( \"Kates kurze Kleider\" );\r\nRunnable out = <b>System.out::println<\/b>;\r\nout.run();<\/pre>\n<p>Ist eine Hauptmethode mit main(String&#8230; args) deklariert, so ist das auch ein Runnable:<\/p>\n<pre>Runnable r = <b>JavaApplication1::main<\/b>;<\/pre>\n<p>Anderes w\u00e4re das bei main(String[]), hier ist ein Parameter zwingend, doch ein Vararg kann auch leer sein.<\/p>\n<p>Statt dass der Name einer Referenzvariablen gew\u00e4hlt wird, kann auch this das Objekt beschreiben und auch super ist m\u00f6glich. this ist praktisch, wenn die Implementierung einer funktionalen Schnittstelle auf eine Methode der eigenen Klasse delegieren m\u00f6chte. Wenn zum Beispiel eine lokale Methode compareTrimmed(\u2026) in der Klassen existieren w\u00fcrde, in der auch der Lambda-Ausdruck steht,\u00a0 und sollte diese Methode als Comparator in Arrays.sort(\u2026) verwendet werden, k\u00f6nnte es hei\u00dfen: Arrays.sort(words, this::compareTrimmed).<\/p>\n<p>Hinweis:\u00a0Es ist nicht m\u00f6glich eine spezielle Methode \u00fcber die Methodenreferenz auszuw\u00e4hlen. Eine Angabe wie String::valueOf oder Arrays::sort ist relativ breit \u2013 bei letzterem w\u00e4hlt der Compiler eine der 18 passenden \u00fcberladen Methoden aus. Da kann es passieren, dass der Compiler eine falsche Methode ausw\u00e4hlt, in dem Fall muss ein expliziter Lambda-Ausdruck eine Mehrdeutigkeit aufl\u00f6sen. Bei generischen Typen kann zum Beispiel List&lt;String&gt;::length oder auch List::length stehen auch hier erkennt der Compiler wieder alles selbst.<\/p>\n<h4>Was soll das alles?<\/h4>\n<p>Einem Einsteiger in die Sprache Java wird dieses Sprache-Feature wie der gr\u00f6\u00dfte Zauber auf Erden vorkommen, und auch Java-Profis bekommen hier zittrige Finger, entweder vor Furcht oder Aufregung\u2026 In der Vergangenheit musste in Java sehr viel Code explizit geschrieben werden, aber mit diesen neuen Methoden-Referenzen erkennt und macht der Compiler vieles von selbst.<\/p>\n<p>N\u00fctzlich wird diese Eigenschaft mit den funktionalen Bibliotheken aus Java 8, die ein eigenes Kapitel einnehmen. Hier nur ein kurzer Vorgeschmack:<\/p>\n<pre>Object[] words = { \" \", '3', null, \"2\", 1, \"\" };\r\nArrays.stream( words )\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 .filter( <b>Objects::nonNull<\/b> )\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 .map( <b>Objects::toString<\/b> )\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 .map( <b>String::trim<\/b> )\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 .filter( s -&gt; ! s.isEmpty() )\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 .map( <b>Integer::parseInt<\/b> )\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 .sorted()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 .forEach( <b>System.out::println<\/b> );\u00a0\u00a0 \/\/ 1 2 3<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Je gr\u00f6\u00dfer Software-Systeme werden, desto wichtiger werden Dinge wie Klarheit, Wiederverwendbarkeit und Dokumentation. Wir haben f\u00fcr unseren String-Comparator eine Implementierung geschrieben, anfangs \u00fcber eine innere Klasse, sp\u00e4ter \u00fcber einen Lambda-Ausdruck. In jedem Fall haben wir Code geschrieben. Doch was w\u00e4re, wenn eine Utility-Klasse schon eine Implementierung mitbringen w\u00fcrde? Dann k\u00f6nnte der Lambda-Ausdruck nat\u00fcrlich an die [&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":[1,11,66],"tags":[],"class_list":["post-2742","post","type-post","status-publish","format-standard","hentry","category-allgemein","category-insel","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\/2742","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=2742"}],"version-history":[{"count":1,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2742\/revisions"}],"predecessor-version":[{"id":2743,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2742\/revisions\/2743"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=2742"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=2742"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=2742"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}