{"id":2763,"date":"2014-03-30T19:11:27","date_gmt":"2014-03-30T17:11:27","guid":{"rendered":"http:\/\/www.tutego.de\/blog\/javainsel\/?p=2763"},"modified":"2014-03-30T19:13:07","modified_gmt":"2014-03-30T17:13:07","slug":"funktionale-schnittstelle-aus-dem-java-util-function-paket","status":"publish","type":"post","link":"https:\/\/www.tutego.de\/blog\/javainsel\/2014\/03\/funktionale-schnittstelle-aus-dem-java-util-function-paket\/","title":{"rendered":"Funktionale Schnittstelle in Java 8 aus java.util.function"},"content":{"rendered":"<p>Funktionen realisieren Abbildungen und da es verschiedene Arten von Abbildungen geben kann, bietet die Java Standardbibliothek im Paket java.util.function f\u00fcr die h\u00e4ufigsten F\u00e4lle funktionale Schnittstellen an. Ein erster \u00dcberblick:<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"382\"><b>Schnittstelle<\/b><\/td>\n<td valign=\"top\" width=\"382\"><b>Abbildung<\/b><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">Consumer&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"382\">(T) \u2192 void<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">DoubleConsumer<\/td>\n<td valign=\"top\" width=\"382\">(double) \u2192 void<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">BiConsumer&lt;T, U&gt;<\/td>\n<td valign=\"top\" width=\"382\">(T, U) \u2192 void<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">Supplier&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"382\">() \u2192 T<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">BooleanSupplier<\/td>\n<td valign=\"top\" width=\"382\">() \u2192 boolean<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">Predicate&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"382\">(T) \u2192 boolean<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">LongPredicate<\/td>\n<td valign=\"top\" width=\"382\">(long) \u2192 boolean<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">BiPredicate&lt;T, U&gt;<\/td>\n<td valign=\"top\" width=\"382\">(T, U) \u2192 boolean<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">Function&lt;T, R&gt;<\/td>\n<td valign=\"top\" width=\"382\">(T) \u2192 R<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">LongToDoubleFunction<\/td>\n<td valign=\"top\" width=\"382\">(long) \u2192 double<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">BiFunction&lt;T, U, R&gt;<\/td>\n<td valign=\"top\" width=\"382\">(T, U) \u2192 R<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">UnaryOperator&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"382\">(T) \u2192 T<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"382\">DoubleBinaryOperator<\/td>\n<td valign=\"top\" width=\"382\">(double) \u2192 boolean<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><em>Beispiele einiger vordefinierter funktionaler Schnittstellen<\/em><\/p>\n<h3><!--more-->Bl\u00f6cke mit Code und die funktionale Schnittstelle java.util.function.Consumer<\/h3>\n<p>Anweisungen von Code lassen sich in eine Methode eines Objekts setzen und auf diese Weise weitergeben. Das ist eine h\u00e4ufige Notwendigkeit, f\u00fcr die das Paket java.util.function eine einfache funktionale Schnittstelle Consumer vorgibt, die einen Konsumenten repr\u00e4sentiert, der Daten annimmt und dann verbraucht (konsumiert).<\/p>\n<div>\n<p>interface java.util.function.<b>Consumer<\/b>&lt;T&gt;<\/p>\n<\/div>\n<ul>\n<li>void accept(T t)<br \/>\nF\u00fchrt Operationen mit der \u00dcbergabe t durch.<\/li>\n<li>default Consumer&lt;T&gt; andThen(Consumer&lt;? super T&gt; after)<br \/>\nLiefert einen neuen Consumer, der erst den aktuellen Consumer ausf\u00fchrt und dann after.<\/li>\n<\/ul>\n<p>Die accept(\u2026)-Methode bekommt ein Argument \u2013 wobei die Implementierung nat\u00fcrlich nicht zwingend darauf zur\u00fcckgreifen muss \u2013 und liefert keine R\u00fcckgabe. Transformationen sind damit nicht m\u00f6glich, denn nur \u00fcber Umwege kann der Konsument die Ergebnisse speichern, und daf\u00fcr ist die Schnittstelle nicht gedacht. Consumer-Typen sind eher gedacht als Endglied einer Kette, in der zum Beispiel Dateien in eine Datei geschrieben werden, die vorher verarbeitet wurden. Diese Seiteneffekte sind beabsichtigt, da sie nach einer Kette von seiteneffektfreien Operationen stehen.<\/p>\n<p>Immer repr\u00e4sentieren Konsumenten Code, und eine API kann nun einfach einen Code-Block nach der Art doSomethingWith(myConsumer) annehmen, und ihn etwa in einem Hintergrund-Thread abzuarbeiten, oder wiederholend auszuf\u00fchren, oder nach einer erlaubten Maximaldauer abbrechen, oder die Zeit messen, oder, oder, oder \u2026<\/p>\n<p>Beispiel:\u00a0Implementiere einen Consumer-Wrapper, der die Ausf\u00fchrungszeit eines anderen Konsumenten loggt.<\/p>\n<pre>import java.util.function.*;<\/pre>\n<pre>import java.util.logging.Logger;<\/pre>\n<pre>class Consumers {<\/pre>\n<pre>\u00a0 public static &lt;T&gt; Consumer&lt;T&gt; measuringConsumer( Consumer&lt;T&gt; block ) {<\/pre>\n<pre>\u00a0\u00a0\u00a0 return t -&gt; {<\/pre>\n<pre>\u00a0 \u00a0\u00a0\u00a0\u00a0long start = System.nanoTime();<\/pre>\n<pre>\u00a0 \u00a0\u00a0\u00a0\u00a0block.accept( t );<\/pre>\n<pre>\u00a0 \u00a0\u00a0\u00a0\u00a0long duration = System.nanoTime() - start;<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0 Logger.getAnonymousLogger().info( \"Ausf\u00fchrungszeit (ns): \" + duration );<\/pre>\n<pre>\u00a0\u00a0\u00a0 };<\/pre>\n<pre>\u00a0 }<\/pre>\n<pre>}<\/pre>\n<p>Folgender Aufruf zeigt die Nutzung:<\/p>\n<pre>Consumer&lt;Void&gt; wrap = measuringConsumer( Void -&gt; System.out.println( \"Test\" ) );\r\nwrap.accept( null );<\/pre>\n<p>Was wir hier implementiert haben ist ein Beispiel vom Execute-Around-Method Muster, bei dem wir um einen Block Code noch etwas anderes legen.<\/p>\n<h4>Typ Consumer in der API<\/h4>\n<p>In der Java-API zeigt sich der Typ Consumer in der Regel als Argument einer Methode forEach(Consumer), die Datenquellen abl\u00e4uft und f\u00fcr jedes Element accept(\u2026) aufruft. Interessant ist die Methode am Typ Iterable, denn die wichtigen Collection-Datenstrukturen wie ArrayList implementieren diese Schnittstelle. So l\u00e4sst sich einfach \u00fcber alle Daten laufen und ein St\u00fcck Code f\u00fcr jedes Element ausf\u00fchren. Auch Iterator hat eine vergleichbare Methode, da hei\u00dft sie forEachRemaining(Consumer) \u2013 das \u201eRemaining\u201c macht deutlich, dass der Iterator schon ein paar next()-Aufrufe erlebt haben k\u00f6nnte, und die Konsumenten daher nicht zwingend die ersten Elemente mitbekommen.<\/p>\n<p>Beispiel:\u00a0Gib jedes Element einer Liste auf der Konsole aus:<\/p>\n<pre>Arrays.asList( 1, 2, 3, 4 ).forEach( System.out::println );<\/pre>\n<h3>Supplier<\/h3>\n<p>Ein Supplier (auch Provider genannt) ist eine Fabrik und sorgt f\u00fcr Objekte. In Java deklariert das Paket java.util.function die funktionale Schnittstelle Supplier f\u00fcr Objektgeber:<\/p>\n<div>\n<p>interface java.util.function.<b>Supplier<\/b>&lt;T&gt;<\/p>\n<\/div>\n<ul>\n<li>T get()<br \/>\nF\u00fchrt Operationen mit der \u00dcbergabe t durch.<\/li>\n<\/ul>\n<p>Weitere statische oder Default-Methoden deklariert Supplier nicht. Was get() nun genau liefert ist Aufgabe der Implementierung und ein Interna. Es k\u00f6nnen neue Objekte sein, immer die gleichen Objekte (Singleton), oder Objekte aus einem Cache.<\/p>\n<h3>Pr\u00e4dikate und java.util.function.Predicate<\/h3>\n<p>Ein Pr\u00e4dikat ist eine Aussage \u00fcber einen Gegenstand, die wahr oder falsch ist. Die Frage mit Character.isDigit(&#8218;a&#8216;), ob das Zeichen \u201ea\u201c eine Ziffer ist, wird mit falsch beantwortet \u2013 isDigit ist also ein Pr\u00e4dikat, weil es \u00fcber einen Gegenstand, einem Zeichen, eine Wahrheitsaussage f\u00e4llen kann.<\/p>\n<p>Flexibler sind Pr\u00e4dikate, wenn sie als Objekte repr\u00e4sentiert werden, weil sie dann an unterschiedliche Stellen weitergegeben werden k\u00f6nnen. Wenn etwa \u00fcber ein Pr\u00e4dikat bestimmt wird, was aus einer Sammlung gel\u00f6scht werden soll oder ob mindestens ein Element in einer Sammlung ist, welches ein Pr\u00e4dikat erf\u00fcllt.<\/p>\n<p>Das java.util.function-Paket<a title=\"\" href=\"file:\/\/\/C:\/Users\/Christian%20Ullenboom\/Dropbox\/Eigene%20Dokumente\/Insel\/todo\/2.Funktionale%20Programmierung,%20ISP,%20zu%20JM.doc#_ftn1\">[1]<\/a> deklariert eine flexible funktionale Schnittstelle Predicate auf folgende Weise:<\/p>\n<div>\n<p>interface java.util.function.<b>Predicate<\/b>&lt;T&gt;<\/p>\n<\/div>\n<ul>\n<li>boolean\u00a0 test(T t)<br \/>\nF\u00fchrt einen Test auf t durch und liefert true, wenn das Kriterium erf\u00fcllt ist, sonst false.<\/li>\n<\/ul>\n<p>Beispiel:\u00a0Der Test, ob ein Zeichen eine Ziffer ist, kann durch Pr\u00e4dikat-Objekte nun auch anders durchgef\u00fchrt werden:<\/p>\n<pre><b>Predicate&lt;<\/b><b>Character<\/b><b>&gt; isDigit<\/b> = c -&gt; Character.isDigit( c );\u00a0 \/\/ kurz: Character::isDigit\r\nSystem.out.println( <b>isDigit.test('a')<\/b> );\u00a0 \/\/ false<\/pre>\n<p>H\u00e4tte es die Schnittstelle Predicate schon fr\u00fcher in Java 1.0 gegeben, h\u00e4tte es\u00a0 der Methode Character.isDigit(\u2026) gar nicht bedurft, es h\u00e4tte auch ein Predicate&lt;Character&gt; als statische Variable in der Klasse Character geben k\u00f6nnen, sodass ein Test dann geschrieben w\u00fcrde als Character.IS_DIGIT.test(\u2026) oder als R\u00fcckgabe von einer Methode Predicate&lt;Character&gt; isDigit(), mit der Nutzung Character.isDigit().test(\u2026). Es ist daher gut m\u00f6glich, dass sich in Zukunft die API dahingehend ver\u00e4ndert, dass Aussagen auf Gegenst\u00e4nden mit Wahrheitsr\u00fcckgabe nicht mehr als Methoden bei den Klassen realisiert werden, sondern als Pr\u00e4dikat-Objekte angeboten werden. Aber Methoden-Referenzen geben zum Gl\u00fcck die Flexibilit\u00e4t, dass problemlos existierende Methoden als Lambda-Ausdr\u00fccke gen\u00fctzt werden k\u00f6nnen und so kommen wir wieder von Methoden zu Funktionen.<\/p>\n<h4>Typ Predicate in der API<\/h4>\n<p>Es gibt in der Java-API einige Stellen, an denen Predicate-Objekte genutzt werden:<\/p>\n<ul>\n<li>Als Argument f\u00fcr L\u00f6sch-Methoden, um in Sammlungen Elemente zu spezifizieren, die gel\u00f6scht oder nach denen gefiltert werden sollen.<\/li>\n<li>Bei den Default-Methoden der Predicate-Schnittstelle selbst, um Pr\u00e4dikate zu verkn\u00fcpfen.<\/li>\n<li>Bei regul\u00e4ren Ausdr\u00fccken: ein Pattern liefert mit asPredicte() ein Predicate f\u00fcr Tests<\/li>\n<li>In der Stream-API, bei der Objekte beim Durchlaufen des Stroms \u00fcber ein Pr\u00e4dikat identifiziert werden, um sie etwa auszufiltern.<\/li>\n<\/ul>\n<p>Beispiel:\u00a0L\u00f6sche aus einer Liste mit Zeichen alle, die Ziffern sind (es bleiben nur Zeichen \u00fcbrig, etwa Buchstaben).<\/p>\n<pre>Predicate&lt;Character&gt; isDigit = Character::isDigit;\r\nList&lt;Character&gt; list = new ArrayList&lt;&gt;( Arrays.asList( 'a', '1' ) );\r\nlist.removeIf( isDigit );<\/pre>\n<h4>Default-Methoden von Predicate<\/h4>\n<p>Es gibt eine Reihe von Default-Methoden, die die funktionale Schnittstelle Predicate anbietet. Zusammenfassend:<\/p>\n<div>\n<p>interface java.util.function.<b>Predicate<\/b>&lt;T&gt;<\/p>\n<\/div>\n<ul>\n<li>default Predicate&lt;T&gt; negate()<br \/>\nLiefert vom aktuellen Pr\u00e4dikat eine Negation. Implementiert als return t -&gt; ! test(t);.<\/li>\n<li>default Predicate&lt;T&gt; and(Predicate&lt;? super T&gt; p)<\/li>\n<li>default Predicate&lt;T&gt; or(Predicate&lt;? super T&gt; p)<br \/>\nUnd\/Oder-Verkn\u00fcpfen das aktuelle Pr\u00e4dikat mit einem anderen Pr\u00e4dikat.<\/li>\n<li>static &lt;T&gt; Predicate&lt;T&gt; isEqual(Object targetRef)<br \/>\nLiefert ein neues Pr\u00e4dikat welches einen Gleichheitstest mit targetRef vornimmt, im Grunde return ref -&gt; Objects.equals(ref, targetRef).<\/li>\n<\/ul>\n<p>Beispiel:\u00a0L\u00f6sche aus einer Liste mit Zeichen alle die, die <i>keine<\/i> Ziffern sind.<\/p>\n<pre>Predicate&lt;Character&gt; isDigit = Character::isDigit;\r\nPredicate&lt;Character&gt; isNotDigit = isDigit.<b>negate()<\/b>;\r\nList&lt;Character&gt; list = new ArrayList&lt;&gt;( Arrays.asList( 'a', '1' ) );\r\nlist.removeIf( isNotDigit );<\/pre>\n<h4>Pr\u00e4dikate aus Pattern<\/h4>\n<p>Seit Java 8 liefert die Pattern-Methode asPredicate() ein Predicate&lt;String&gt;, so dass ein regul\u00e4rer Ausdruck als Kriterium zum Beispiel zum Filtern oder L\u00f6schen von Eintr\u00e4gen in Datenstrukturen genutzt werden kann.<\/p>\n<h3>Funktionen und die allgemeine funktionale Schnittstelle java.util.function.Function<\/h3>\n<p>Funktionen im Sinne der funktionalen Programmierung k\u00f6nnen in verschiedenen Bauarten vorkommen: mit Parameterliste \/ R\u00fcckgabe oder ohne. Doch im Grunde sind es Spezialformen, und die funktionale Schnittstelle java.util.function.Function ist die allgemeinste, die zu einem Argument ein Ergebnis liefert.<\/p>\n<div>\n<p>interface java.util.function.<b>Function<\/b>&lt;T, R&gt;<\/p>\n<\/div>\n<ul>\n<li>R\u00a0\u00a0 apply(T t)<br \/>\nWendet eine Funktion an und liefert zur Eingabe t eine R\u00fcckgabe.<\/li>\n<\/ul>\n<p>Beispiel:Eine Funktion zur Bestimmung des Maximums:<\/p>\n<pre><b>Function&lt;Double, Double&gt;<\/b> max = a -&gt; Math.abs( a );\u00a0 \/\/ alternativ Math::abs\r\nSystem.out.println( <b>max.apply( -12. )<\/b> );\u00a0 \/\/ 12.0<\/pre>\n<p>Auch bei Funktionen ergibt sich f\u00fcr das API-Design ein Spannungsfeld, denn im Grunde m\u00fcssen \u201eFunktionen\u201c nun gar nicht mehr als Methoden angeboten werden, sondern Klassen k\u00f6nnten sie auch als Function-Objekte anbieten. Doch da Methoden-Referenzen problemlos die Br\u00fccke von Methodennamen zu Objekten schlagen, fahren Entwickler mit klassischen Methoden ganz gut.<\/p>\n<h4>Typ Function in der API<\/h4>\n<p>Die Stream-API ist der gr\u00f6\u00dfte Nutznie\u00dfer vom Function-Typ. Es finden sich einige wenige Beispiele bei Objekt-Vergleichen (Comparator), im Paket f\u00fcr Nebenl\u00e4ufigkeiten und bei Assoziativspeichern. Im Abschnitt \u00fcber die Stream-API werden wir daher viele weitere Beispiele kennenlernen.<\/p>\n<p>Beispiel:\u00a0Ein Assoziativspeicher soll als Cache realisiert werden, der zu Dateinamen den Inhalt assoziiert. Ist zu dem Schl\u00fcssel (dem Dateinamen) noch kein Inhalt vorhanden, soll dieser in den Assoziativspeicher gelegt werden.<\/p>\n<pre>class FileCache {<\/pre>\n<pre>\u00a0 private Map&lt;String, byte[]&gt; map = new HashMap&lt;&gt;();<\/pre>\n<pre>\u00a0 public byte[] getContent( String filename ) {<\/pre>\n<pre>\u00a0\u00a0\u00a0 return map.computeIfAbsent( filename, file -&gt; {<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0 try {<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return Files.readAllBytes( Paths.get( file ) );<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0 } catch ( IOException e ) { throw new UncheckedIOException( e ); }<\/pre>\n<pre>\u00a0\u00a0\u00a0 } );<\/pre>\n<pre>\u00a0 }<\/pre>\n<pre>}<\/pre>\n<p>Zu der Methode kommt das Kapitel \u00fcber Datenstrukturen noch einmal zur\u00fcck, das Beispiel soll nur eine Idee geben, dass Funktionen an andere Funktionen \u00fcbergeben werden \u2013 hier eine Function&lt;String, byte[]) an computeIfAbsent(\u2026). Sobald an den Datei-Cache der Aufruf getContent(String)geht, wird dieser die Map fragen und wenn diese zu dem Schl\u00fcssel keinen Wert hat, wird sie den Lambda-Ausdruck auswerten, um zu dem Dateinamen den Inhalt zu liefern.<b><\/b><\/p>\n<h4>Getter-Methoden als Function \u00fcber Methoden-Referenzen<\/h4>\n<p>Methoden-Referenzen geh\u00f6ren zu den st\u00e4rksten Sprachmitteln von Java 8. In Kombination mit Gettern ist ein Muster abzulesen, welches oft in Code zu sehen ist. Zun\u00e4chst noch einmal zur Wiederholung von Function und der Nutzung bei Methoden-Referenzen:<\/p>\n<pre>Function&lt;<b>String<\/b>, String&gt; func2a = (<b>String<\/b> s) -&gt; s.toUpperCase();<\/pre>\n<pre>Function&lt;<b>String<\/b>, String&gt; func2b = <b>String::toUpperCase<\/b>;<\/pre>\n<pre><\/pre>\n<pre>Function&lt;<b>Point<\/b>, Double&gt; func1a = (<b>Point<\/b> p) -&gt; p.getX();<\/pre>\n<pre>Function&lt;<b>Point<\/b>, Double&gt; func1b = <b>Point::getX<\/b>;<\/pre>\n<pre><\/pre>\n<pre>System.out.println( func2b.apply( \"jocelyn\" ) ); \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ JOCELYN<\/pre>\n<pre>System.out.println( func1b.apply( new Point( 9, 0 ) ) ); \/\/ 9.0<\/pre>\n<p>Dass Function auf die gegebene Methoden-Referenz passt, ist auf den ersten Blick unverst\u00e4ndlich, da die Signaturen von toUpperCase() und getX() keinen Parameter deklarieren, also im \u00fcblichen Sinne keine Funktionen sind, wo etwas reinkommt und wieder rauskommt. Wir haben es hier aber mit einem speziellen Fall zu tun, denn die in der Methoden-Referenz genannten Methoden sind a) nicht statisch \u2013 wie Math::max \u2013 und b) es ist auch keine Referenz \u2013 wie System.out::print \u2013 im Spiel, sondern hier wird der Compiler eine Objektmethode auf genau dem Objekt aufrufen was als erstes Argument der funktionalen Schnittstelle \u00fcbergeben wurde. (Diesen Satz bitte zweimal lesen.)<\/p>\n<p>Damit ist Function ein praktischer Typ bei allen Szenarien, bei denen irgendwie \u00fcber Getter Zust\u00e4nde erfragt werden, wie es etwa bei einem Comparator \u00f6fters vorkommt. Hier ist eine statische Methode \u00a0\u2013 die Generics einmal ausgelassen \u2013 Comparator&lt;\u2026&gt; Comparator.comparing(Function&lt;\u2026&gt; keyExtractor) sehr n\u00fctzlich.<\/p>\n<p>Beispiel:\u00a0Besorge eine Liste von Pakten, die vom Klassenlader zug\u00e4nglich sind, und sortiere sie nach Namen:<\/p>\n<pre>List&lt;Package&gt; list = Arrays.asList( Package.getPackages() );\r\nCollections.sort( list, <b>Comparator.comparing( Package::getName )<\/b> );\r\nSystem.out.println( list ); \/\/ [package java.io, \u2026 sun.util.locale \u2026<\/pre>\n<h4>Default-Methoden in Function<\/h4>\n<p>Die funktionale Schnittstelle schreibt nur eine Methode apply(\u2026) vor, deklariert jedoch noch drei zus\u00e4tzliche Default-Methoden:<\/p>\n<div>\n<p>interface java.util.function.<b>Function<\/b>&lt;T,R&gt;<\/p>\n<\/div>\n<ul>\n<li>static &lt;T&gt; Function&lt;T,T&gt; identity()<br \/>\nLiefert eine neue Funktion, die immer die Eingabe als Ergebnis liefert.<\/li>\n<li>default &lt;V&gt; Function&lt;T,V&gt; andThen(Function&lt;? super R,? extends V&gt; after)<br \/>\nEntspricht t -&gt; after.apply(apply(t)).<\/li>\n<li>default &lt;V&gt; Function&lt;V,R&gt; compose(Function&lt;? super V,? extends T&gt; before)<br \/>\nEntspricht v -&gt; apply(before.apply(v)).<\/li>\n<\/ul>\n<p>Die Methoden andThen(\u2026) und compose(\u2026) unterscheiden sich also darin, in welcher Reihenfolge die Funktionen aufgerufen werden. Das Gute ist, dass die Parameternamen (\u201ebefore\u201c, \u201eafter\u201c) klarmachen, was hier in welcher Reihenfolge aufgerufen wird, wenn auch selbst \u201ecompose\u201c wenig aussagt.<\/p>\n<h4>Function vs. Consumer\/Predicate , UnaryOperator<\/h4>\n<p>Im Grunde l\u00e4sst sich alles als Function darstellen, denn<\/p>\n<ul>\n<li>ein Consumer&lt;T&gt; l\u00e4sst sich auch als Function&lt;T,Void&gt; verstehen (es geht etwas rein, aber nichts raus),<\/li>\n<li>ein Predicate&lt;T&gt; als Function&lt;T,Boolean&gt;,<\/li>\n<li>ein Supplier&lt;T&gt; als Function&lt;Void,T&gt;.<\/li>\n<\/ul>\n<p>Dennoch erf\u00fcllen diese speziellen Typen voll ihren Zweck, denn je genauer der Typ, desto besser.<\/p>\n<p>Es gibt auch eine weitere Schnittstelle im java.util.function-Paket, die Function spezialisiert und zwar UnaryOperator. Ein UnaryOperator ist eine spezielle Funktion bei der die Typen f\u00fcr \u201eEingang\u201c und \u201eAusgang\u201c gleich sind.<\/p>\n<div>\n<p>interface java.util.function.<b>UnaryOperator<\/b>&lt;T&gt;<\/p>\n<p>extends Function&lt;T,T&gt;<\/p>\n<\/div>\n<ul>\n<li>static &lt;T&gt; UnaryOperator&lt;T&gt; identity()<br \/>\nLiefert den Identit\u00e4ts-Operator, der alle Eingaben auf die Ausgaben abbildet.<\/li>\n<\/ul>\n<p>Die generischen Typen machen deutlich, dass der Typ des Methodenparameters gleich dem Ergebnistyp ist. Bis auf identity() gibt es keine weitere Funktionalit\u00e4t, die Schnittstelle dient lediglich zur Typdeklaration.<\/p>\n<p>An einigen Stellen der Java-Bibliothek kommt dieser Typ auch vor, etwa bei der Methode replaceAll(UnaryOperator) der List-Typen.<\/p>\n<p>Beispiel:\u00a0Verdopple in der Liste jeden Eintrag.<\/p>\n<pre>List&lt;Integer&gt; list = Arrays.asList( 1, 2, 3 );\r\nlist.replaceAll( e -&gt; e * 2 );\r\nSystem.out.println( list );\u00a0 \/\/ [2, 4, 6]<\/pre>\n<h3>Ein bisschen Bi \u2026<\/h3>\n<p>Bi ist eine bekannte lateinische Vorsilbe f\u00fcr \u201ezwei\u201c, was \u00fcbertragen auf die Typen aus java.util.function bedeutet, das statt einem Argument zwei \u00fcbergeben werden k\u00f6nnen.<\/p>\n<table width=\"79%\" border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"16%\"><b>Typ<\/b><\/td>\n<td valign=\"top\" width=\"43%\"><b>Schnittstelle<\/b><\/td>\n<td valign=\"top\" width=\"39%\"><b>Operation<\/b><b><\/b><\/td>\n<\/tr>\n<tr>\n<td rowspan=\"2\" valign=\"top\" width=\"16%\">Konsument<\/td>\n<td valign=\"top\" width=\"43%\">Consumer&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"39%\">void accept(T t)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"43%\">BiConsumer&lt;T,<b>U<\/b>&gt;<\/td>\n<td valign=\"top\" width=\"39%\">void accept(T t, <b>U u<\/b>)<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"2\" valign=\"top\" width=\"16%\">Funktion<\/td>\n<td valign=\"top\" width=\"43%\">Function&lt;T,<b>R<\/b>&gt;<\/td>\n<td valign=\"top\" width=\"39%\">R apply(T t)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"43%\">BiFunction&lt;T,<b>U<\/b>,R&gt;<\/td>\n<td valign=\"top\" width=\"39%\">R apply(T t, <b>U u<\/b>)<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"2\" valign=\"top\" width=\"16%\">Pr\u00e4dikat<\/td>\n<td valign=\"top\" width=\"43%\">Predicate&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"39%\">boolean test(T t)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"43%\">BiPredicate&lt;T,<b>U<\/b>&gt;<\/td>\n<td valign=\"top\" width=\"39%\">boolean test(T t, <b>U u<\/b>)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><em>Ein-\/Zwei-Argument Methoden Vergleich<\/em><\/p>\n<p>Die Bi-Typen haben mit den nicht-Bi-Typen keine Typbeziehung.<a title=\"\" href=\"file:\/\/\/C:\/Users\/Christian%20Ullenboom\/Dropbox\/Eigene%20Dokumente\/Insel\/todo\/2.Funktionale%20Programmierung,%20ISP,%20zu%20JM.doc#_ftn2\">[2]<\/a><\/p>\n<h4>BiConsumer<\/h4>\n<p>Der BiConsumer deklariert die Methode accept(T, U) mit zwei Parametern, die jeweils unterschiedliche Typen tragen k\u00f6nnen. Haupteinsatzpunkt des Typs in der Java Standardbibliothek sind Assoziativspeicher, die Schl\u00fcssel und Werte an accept(\u2026) \u00fcbergeben. So deklariert Map die Methode:<\/p>\n<div>\n<p>interface java.util.<b>Map<\/b>&lt;K,V&gt;<\/p>\n<\/div>\n<ul>\n<li>default void forEach(BiConsumer&lt;? super K,? super V&gt; action)<br \/>\nL\u00e4uft den Assoziativspeicher ab und ruft auf jedem Schl\u00fcssel-Werte-Paar die accept(\u2026)-Methode vom \u00fcbergebenen BiConsumer auf.<\/li>\n<\/ul>\n<p>Beispiel:\u00a0Gib die Temperaturen der St\u00e4dte aus:<\/p>\n<pre>Map&lt;String, Integer&gt; map = new HashMap&lt;&gt;();\r\nmap.put( \"Manila\", 25 )\r\nmap.put( \"Leipzig\", -5 );\r\nmap.forEach( (k,v) -&gt; System.out.printf(\"%s hat %d Grad%n\", k, v) );<\/pre>\n<p>Ein BiConsumer besitzt eine Default-Methode andThen(&#8230;), wie auch der Consumer sie zur Verkettung deklariert.<\/p>\n<div>\n<p>interface java.util.function.<b>BiConsumer<\/b>&lt;T,U&gt;<\/p>\n<\/div>\n<ul>\n<li>default BiConsumer&lt;T,U&gt; andThen(BiConsumer&lt;? super T,? super U&gt; after)<br \/>\nVerkn\u00fcpft den aktuellen BiConsumer mit after zu einem neunen BiConsumer.<\/li>\n<\/ul>\n<h4>BiFunction und BinaryOperator<\/h4>\n<p>Eine BiFunction ist eine Funktion mit zwei Argumenten, w\u00e4hrend eine normale Function nur ein Argument annimmt.<\/p>\n<p>Beispiel:\u00a0Nutzung von Function und BiFunction mit Methoden-Referenzen.<\/p>\n<pre>Function&lt;Double, Double&gt; sign = Math::abs;\r\nBiFunction&lt;Double, Double, Double&gt; max = Math::max;<\/pre>\n<p>Die Java-Bibliothek greift viel \u00f6fters auf Function zur\u00fcck als auf BiFunction. Der h\u00e4ufigste Einsatz findet sich in der Standardbibliothek rund um Assoziativspeicher, bei denen Schl\u00fcssel und Wert an eine BiFunction \u00fcbergeben werden.<\/p>\n<p>Beispiel:\u00a0Konvertiere alle assoziierten Werte einer HashMap in Gro\u00dfschreibung.<\/p>\n<pre>Map&lt;Integer, String&gt; map = new HashMap&lt;&gt;();\r\nmap.put( 1, \"eins\" ); map.put( 2, \"zwEi\" );\r\nSystem.out.println( map );\u00a0 \/\/ {1=eins, 2=zwEi}\r\nBiFunction&lt;Integer, String, String&gt; func = (k, v) -&gt; v.toUpperCase();\r\nmap.replaceAll( func );\r\nSystem.out.println( map );\u00a0 \/\/ {1=EINS, 2=ZWEI}<\/pre>\n<p>Ist bei einer Function der Typ derselbe, bietet die Java-API daf\u00fcr den spezielleren Typ UnaryOperator. Sind bei einer BiFunction alle drei Typen gleich, bietet sich hier BinaryOperator an \u2013 zum Vergleich:<\/p>\n<ul>\n<li>interface UnaryOperator&lt;T&gt; extends Function&lt;T,T&gt;<\/li>\n<li>interface BinaryOperator&lt;T&gt; extends BiFunction&lt;T,T,T&gt;<\/li>\n<\/ul>\n<p>Beispiel:\u00a0BiFunction und BinaryOperator:<\/p>\n<pre>BiFunction&lt;Double, Double, Double&gt; max1 = Math::max;\r\nBinaryOperator&lt;Double&gt; \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0max2 = Math::max;<\/pre>\n<p>BinaryOperator spielt bei sogenannten Reduktionen eine gro\u00dfe Rolle, wenn zum Beispiel wie bei max aus zwei Werten einer wird, auch das beleuchtet der Abschnitt \u00fcber die Stream-API sp\u00e4ter genauer.<\/p>\n<p>Die Schnittstelle BiFunction deklariert genau eine Default-Methode:<\/p>\n<div>\n<p>interface java.util.function.<b>BiFunction<\/b>&lt;T,U,R&gt;<\/p>\n<p>extends Function&lt;T, T&gt;<\/p>\n<\/div>\n<ul>\n<li>default &lt;V&gt; BiFunction&lt;T,U,V&gt; andThen(Function&lt;? super R,? extends V&gt; after)<\/li>\n<\/ul>\n<p>BinaryOperator dagegen zwei statische Methoden:<\/p>\n<div>\n<p>public interface java.util.function.<b>BinaryOperator<\/b>&lt;T&gt;<\/p>\n<p>extends BiFunction&lt;T,T,T&gt;<\/p>\n<\/div>\n<ul>\n<li>static &lt;T&gt; BinaryOperator&lt;T&gt; maxBy(Comparator&lt;? super T&gt; comparator)<\/li>\n<li>static &lt;T&gt; BinaryOperator&lt;T&gt; minBy(Comparator&lt;? super T&gt; comparator)<br \/>\nLiefert einen BinaryOperator, der das Maximum\/Minimum bez\u00fcglich eines gegebenes comparator liefert.<\/li>\n<\/ul>\n<h4>BiPredicate<\/h4>\n<p>Ein BiPredicate testet zwei Argumente und verdichtet sie zu einem Wahrheitswert. Wie Predicate deklariert auch BiPredicate drei Default-Methoden and(\u2026), or(\u2026) und negate(\u2026), wobei nat\u00fcrlich eine statische isEqual(\u2026)-Methode wie bei Predicate in BiPredicate fehlt. F\u00fcr BiPredicate gibt es in der Java-Standardbibliothek nur eine Verwendung bei einer Methode zum Finden von Dateien \u2013 der Gebrauch ist selten, zudem ja auch ein Pr\u00e4dikat immer einer Funktion mit boolean-R\u00fcckgabe ist, sodass es eigentlich f\u00fcr diese Schnittstelle keine zwingende Notwendigkeit gibt.<\/p>\n<p>Beispiel:\u00a0Bei BiXXX und zwei Argumenten h\u00f6rt im \u00dcbrigen die Spezialisierung auf, es gibt keine Typen TriXXX, QuardXXX, \u2026. Das ist in der Praxis auch nicht n\u00f6tig, denn zum Einen kann oftmals eine Reduktion stattfinden, so ist etwa max(1, 2,3) gleich max(1, max(2, 3)) und zum Zweiten kann auch der Parametertyp eine Sammlung sein, wie in Function&lt;List&lt;Integer&gt;, Integer&gt; max.<\/p>\n<h3>Funktionale Schnittstellen mit Primitiven<\/h3>\n<p>Die bisher vorgestellten funktionalen Schnittstellen sind durch die generischen Typparameter sehr flexibel, aber was fehlt, sind Signaturen mit Primitiven \u2013 Java hat das \u201eProblem\u201c, dass Generics nur mit Referenztypen funktioniert, nicht aber mit primitiven Typen. Aus diesem Grund gibt es von fast allen Schnittstellen aus dem function-Paket vier Versionen; eine generische f\u00fcr beliebige Referenzen, sowie Versionen f\u00fcr den Typ int, long und double. Die API-Designer wollten gerne die Wrapper-Typen au\u00dfen vor lassen und gewisse primitive Typen unterst\u00fctzen.<\/p>\n<p>Die folgende Tabelle gibt einen \u00dcberblick \u00fcber die funktionalen Schnittstellen, die alle keinerlei Vererbungsbeziehungen zu anderen Schnittstellen haben.<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"263\"><b>Funktionale Schnittstelle<\/b><\/td>\n<td valign=\"top\" width=\"450\"><b>Funktions-Deskriptor<\/b><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\" valign=\"top\" width=\"713\"><b>XXXSupplier<\/b><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">BooleanSupplier<\/td>\n<td valign=\"top\" width=\"450\">boolean getAsBoolean()<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">IntSupplier<\/td>\n<td valign=\"top\" width=\"450\">int getAsInt()<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">LongSupplier<\/td>\n<td valign=\"top\" width=\"450\">long getAsLong()<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">DoubleSupplier<\/td>\n<td valign=\"top\" width=\"450\">double getAsDouble()<\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\" valign=\"top\" width=\"713\"><b>XXXConsumer<\/b><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">IntConsumer<\/td>\n<td valign=\"top\" width=\"450\">void accept(int value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">LongConsumer<\/td>\n<td valign=\"top\" width=\"450\">void accept(long value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">DoubleConsumer<\/td>\n<td valign=\"top\" width=\"450\">void accept(double value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ObjIntConsumer&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"450\">void accept(T t, int value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ObjLongConsumer&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"450\">void accept(T t, long value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ObjDoubleConsumer&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"450\">void accept(T t, double value)<\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\" valign=\"top\" width=\"713\"><b>XXXPredicate<\/b><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">IntPredicate<\/td>\n<td valign=\"top\" width=\"450\">boolean test(int value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">LongPredicate<\/td>\n<td valign=\"top\" width=\"450\">boolean test(long value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">DoublePredicate<\/td>\n<td valign=\"top\" width=\"450\">boolean test(double value)<\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\" valign=\"top\" width=\"713\"><b>XXXFunction<\/b><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">DoubleToIntFunction<\/td>\n<td valign=\"top\" width=\"450\">int applyAsInt(double value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">IntToDoubleFunction<\/td>\n<td valign=\"top\" width=\"450\">double applyAsDouble(int value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">LongToIntFunction<\/td>\n<td valign=\"top\" width=\"450\">int applyAsInt(long value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">IntToLongFunction<\/td>\n<td valign=\"top\" width=\"450\">long applyAsLong(int value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">DoubleToLongFunction<\/td>\n<td valign=\"top\" width=\"450\">long applyAsLong(double value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">LongToDoubleFunction<\/td>\n<td valign=\"top\" width=\"450\">double applyAsDouble(long value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">IntFunction&lt;R&gt;<\/td>\n<td valign=\"top\" width=\"450\">R apply(int value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">LongFunction&lt;R&gt;<\/td>\n<td valign=\"top\" width=\"450\">R apply(long value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">DoubleFunction&lt;R&gt;<\/td>\n<td valign=\"top\" width=\"450\">R apply(double value)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ToIntFunction&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"450\">int applyAsInt(T t)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ToLongFunction&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"450\">long applyAsLong(T t)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ToDoubleFunction&lt;T&gt;<\/td>\n<td valign=\"top\" width=\"450\">double applyAsDouble(T t)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ToIntBiFunction&lt;T,U&gt;<\/td>\n<td valign=\"top\" width=\"450\">int applyAsInt(T t, U u)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ToLongBiFunction&lt;T,U&gt;<\/td>\n<td valign=\"top\" width=\"450\">long applyAsLong(T t, U u)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">ToDoubleBiFunction&lt;T,U&gt;<\/td>\n<td valign=\"top\" width=\"450\">double applyAsDouble(T t, U u)<\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\" valign=\"top\" width=\"713\"><b>XXXOperator<\/b><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">IntUnaryOperator<\/td>\n<td valign=\"top\" width=\"450\">int applyAsInt(int operand)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">LongUnaryOperator<\/td>\n<td valign=\"top\" width=\"450\">long applyAsLong(long operand)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">DoubleUnaryOperator<\/td>\n<td valign=\"top\" width=\"450\">double applyAsDouble(double operand)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">IntBinaryOperator<\/td>\n<td valign=\"top\" width=\"450\">int applyAsInt(int left, int right)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">LongBinaryOperator<\/td>\n<td valign=\"top\" width=\"450\">long applyAsLong(long left, long right)<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"263\">DoubleBinaryOperator<\/td>\n<td valign=\"top\" width=\"450\">double applyAsDouble(double left, double right)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><em>Spezielle funktionale Schnittstellen f\u00fcr primitive Werte<\/em><\/p>\n<h4>Statische und Default-Methoden<\/h4>\n<p>Einige generisch deklarierte funktionale Schnittstellen Typen besitzen Default-Methoden bzw. statische Methoden besitzen, und \u00e4hnliches findet sich auch bei den primitiven funktionalen Schnittstellen wieder:<\/p>\n<p>Die XXXConsumer-Schnittstellen deklarieren default XXXConsumer andThen(XXXConsumer after), aber nicht die ObjXXXConsumer-Typen, sie besitzen keine Default-Methode.<\/p>\n<p>Die XXXPredicate-Schnittstellen deklarieren<\/p>\n<ul>\n<li>default XXXPredicate negate()<\/li>\n<li>default XXXPredicate and(XXXPredicate other)<\/li>\n<li>default IntPredicate or(XXXPredicate other).<\/li>\n<\/ul>\n<p>Jeder XXXUnaryOperator besitzt<\/p>\n<ul>\n<li>default XXXUnaryOperator andThen(IntUnaryOperator after)<\/li>\n<li>default XXXUnaryOperator compose(XXXUnaryOperator before) und<\/li>\n<li>static IntUnaryOperator identity().<\/li>\n<\/ul>\n<p>BinaryOperator hat zwei statischen Methoden maxBy(\u2026) und minBy(\u2026), die es nicht in der primitiven Version XXXBinaryOperator gibt, da kein Comparator bei primitiven Vergleichen n\u00f6tig ist.<\/p>\n<p>Die XXXSupplier-Schnittstellen deklarieren keine statische- oder Default-Methoden, genauso wie es auch Supplier nicht tut.<\/p>\n<div><br clear=\"all\" \/><\/p>\n<hr align=\"left\" size=\"1\" width=\"33%\" \/>\n<div>\n<p><a title=\"\" href=\"file:\/\/\/C:\/Users\/Christian%20Ullenboom\/Dropbox\/Eigene%20Dokumente\/Insel\/todo\/2.Funktionale%20Programmierung,%20ISP,%20zu%20JM.doc#_ftnref1\">[1]<\/a> \u00a0\u00a0\u00a0\u00a0 Achtung, in javax.sql.rowset gibt es ebenfalls eine Schnittstelle Predicate.<\/p>\n<\/div>\n<div>\n<p><a title=\"\" href=\"file:\/\/\/C:\/Users\/Christian%20Ullenboom\/Dropbox\/Eigene%20Dokumente\/Insel\/todo\/2.Funktionale%20Programmierung,%20ISP,%20zu%20JM.doc#_ftnref2\">[2]<\/a> \u00a0\u00a0\u00a0\u00a0 Irgendwie finden das manche Leser lustig \u2026<\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Funktionen realisieren Abbildungen und da es verschiedene Arten von Abbildungen geben kann, bietet die Java Standardbibliothek im Paket java.util.function f\u00fcr die h\u00e4ufigsten F\u00e4lle funktionale Schnittstellen an. Ein erster \u00dcberblick: Schnittstelle Abbildung Consumer&lt;T&gt; (T) \u2192 void DoubleConsumer (double) \u2192 void BiConsumer&lt;T, U&gt; (T, U) \u2192 void Supplier&lt;T&gt; () \u2192 T BooleanSupplier () \u2192 boolean Predicate&lt;T&gt; (T) [&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,66],"tags":[],"class_list":["post-2763","post","type-post","status-publish","format-standard","hentry","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\/2763","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=2763"}],"version-history":[{"count":4,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2763\/revisions"}],"predecessor-version":[{"id":2767,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/posts\/2763\/revisions\/2767"}],"wp:attachment":[{"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/media?parent=2763"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/categories?post=2763"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tutego.de\/blog\/javainsel\/wp-json\/wp\/v2\/tags?post=2763"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}