-
Notifications
You must be signed in to change notification settings - Fork 0
/
lambda-funktionale-interfaces.html
18 lines (17 loc) · 14.8 KB
/
lambda-funktionale-interfaces.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html><html lang="de-ch"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Lambda Funktionale Interfaces - Finecloud</title><meta name="description" content="Lambda Interfaces sind häufig benötigte Lambda-Ausdrücke, die Teil des JDKs sind und damit nicht in jedem Projekt wieder neu angelegt werden müssen. Zum Beispiel kann mit dieser Methode eine Summe aus Objekten berechnet werden: public static <T> long summiere(List<T> tees, ToIntFunction<T> func){ long result =…"><meta name="generator" content="Publii Open-Source CMS for Static Site"><link rel="stylesheet" href="https://www.finecloud.ch/media/plugins/syntaxHighlighter/prism-black.css"><link rel="canonical" href="https://www.finecloud.ch/lambda-funktionale-interfaces.html"><link rel="alternate" type="application/atom+xml" href="https://www.finecloud.ch/feed.xml"><link rel="alternate" type="application/json" href="https://www.finecloud.ch/feed.json"><meta property="og:title" content="Lambda Funktionale Interfaces"><meta property="og:site_name" content="Finecloud"><meta property="og:description" content="Lambda Interfaces sind häufig benötigte Lambda-Ausdrücke, die Teil des JDKs sind und damit nicht in jedem Projekt wieder neu angelegt werden müssen. Zum Beispiel kann mit dieser Methode eine Summe aus Objekten berechnet werden: public static <T> long summiere(List<T> tees, ToIntFunction<T> func){ long result =…"><meta property="og:url" content="https://www.finecloud.ch/lambda-funktionale-interfaces.html"><meta property="og:type" content="article"><link rel="shortcut icon" href="https://www.finecloud.ch/media/website/finecloud.png" type="image/png"><link rel="stylesheet" href="https://www.finecloud.ch/assets/css/style.css?v=39da73365516a098a9b73b721fc970e2"><script type="application/ld+json">{"@context":"http://schema.org","@type":"Article","mainEntityOfPage":{"@type":"WebPage","@id":"https://www.finecloud.ch/lambda-funktionale-interfaces.html"},"headline":"Lambda Funktionale Interfaces","datePublished":"2022-05-30T14:21","dateModified":"2022-06-20T07:13","description":"Lambda Interfaces sind häufig benötigte Lambda-Ausdrücke, die Teil des JDKs sind und damit nicht in jedem Projekt wieder neu angelegt werden müssen. Zum Beispiel kann mit dieser Methode eine Summe aus Objekten berechnet werden: public static <T> long summiere(List<T> tees, ToIntFunction<T> func){ long result =…","author":{"@type":"Person","name":"Finecloud","url":"https://www.finecloud.ch/authors/finecloud/"},"publisher":{"@type":"Organization","name":"Finecloud"}}</script><meta name="google-site-verification" content="seFY9U12uiEq5U3_MyZiX6XWzk0AVFl9zITr2ZKsytY"></head><body><div class="site-container"><header class="top" id="js-header"><a class="logo" href="https://www.finecloud.ch/">Finecloud</a><nav class="navbar js-navbar"><button class="navbar__toggle js-toggle" aria-label="Menu" aria-haspopup="true" aria-expanded="false"><span class="navbar__toggle-box"><span class="navbar__toggle-inner">Menu</span></span></button><ul class="navbar__menu"><li><a href="https://www.finecloud.ch/" target="_self">Blog</a></li><li><a href="https://www.finecloud.ch/tags/" target="_self">Tags</a></li></ul></nav><div class="search"><div class="search__overlay js-search-overlay"><div class="search__overlay-inner"><form action="https://www.finecloud.ch/search.html" class="search__form"><input class="search__input js-search-input" type="search" name="q" placeholder="search..." aria-label="search..." autofocus="autofocus"></form><button class="search__close js-search-close" aria-label="Close">Close</button></div></div><button class="search__btn js-search-btn" aria-label="Search"><svg role="presentation" focusable="false"><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#search"/></svg></button></div></header><main><article class="post"><div class="hero"><figure class="hero__image hero__image--overlay"><img src="https://www.finecloud.ch/media/website/download.jpg" srcset="https://www.finecloud.ch/media/website/responsive/download-xs.jpg 300w, https://www.finecloud.ch/media/website/responsive/download-sm.jpg 480w, https://www.finecloud.ch/media/website/responsive/download-md.jpg 768w, https://www.finecloud.ch/media/website/responsive/download-lg.jpg 1024w, https://www.finecloud.ch/media/website/responsive/download-xl.jpg 1360w, https://www.finecloud.ch/media/website/responsive/download-2xl.jpg 1600w" sizes="100vw" loading="eager" alt=""></figure><header class="hero__content"><div class="wrapper"><div class="post__meta"><time datetime="2022-05-30T14:21">Mai 30, 2022</time></div><h1>Lambda Funktionale Interfaces</h1></div></header></div><div class="wrapper post__entry"><div class="post__toc"><h3>Table of Contents</h3><ul><li><a href="#mcetoc_1g4tdtt405pg">Function</a></li><li><a href="#mcetoc_1g4tdtt405ph">Predicate</a></li><li><a href="#mcetoc_1g4tdtt405pi">Consumer</a></li><li><a href="#mcetoc_1g4tdtt405pj">Supplier</a></li><li><a href="#mcetoc_1g4tdtt405pk">BiFunction, BiPredicate, BiConsumer</a></li></ul></div><p>Lambda Interfaces sind häufig benötigte Lambda-Ausdrücke, die Teil des JDKs sind und damit nicht in jedem Projekt wieder neu angelegt werden müssen.</p><p>Zum Beispiel kann mit dieser Methode eine Summe aus Objekten berechnet werden:</p><p><code>public static <T> long summiere(List<T> tees, ToIntFunction<T> func){</code><br><code> long result = 0;</code><br><code> for (T tee : tees){</code><br><code> result += func.applyAsInt(tee);</code><br><code> }</code><br><code> return result;</code><br><code>}</code></p><p>Alle Interfaces die Lambda-Ausdrücke ermöglichen, sind Bestandteil des Packages java.util.function. Darin sind rund 40 Interfaces enthalten. Eine konsequente Namenskonvention hilft den Überblick zu behalten. Dabei werden die Interfaces grundlegend nach der Form benannt, also nach Parametern und Rückgabewerten. Diese grundlegenden Interfaces arbeiten mit Objekten. Für Interfaces, die dieselbe Operation für Primitive bereitstellen, wird der Name des primitiven Typs vorangestellt:</p><ul><li>Function<T, R> erwartet ein Objekt vom Typ T als Parameter und gibt ein Objekt vom Typ R zurück.</li><li>ToIntFunction<T> erwartet ein Objekt vom Typ T als Parameter und gibt einen int-Wert zurück.</li><li>DoubleToIntFunction erwartet einen double-Wert als Parameter und gibt einen int-Wert zurück.</li></ul><p>Nicht alle möglichen Kombinationen stehen zur Verfügung, aber die am häufigsten gebrauchten sind da. Nachfolgend schauen wir uns die grundlegenden Formen von funktionalen Interfaces an.</p><h3 id="mcetoc_1g4tdtt405pg">Function</h3><p>Funktionsobjekte entsprechen in etwa der mathematischen Definition von einstelligen Funktionen: Sie bilden einen Wert auf einen anderen ab. Eine einfache Function ist eine Abbildung von einem Objekt auf ein anderes Objekt, eine ToIntFunction eine Abbildung von einem Objekt auf einen int-Wert usw.</p><p>Im vorherigen Codebeispiel haben wir eine Anwendung für ToIntFuntion gesehen, dort werden Objekte auf einen Int-Wert abgebildet, der anschliessend zu einer laufenden Summe addiert wird. Auch die Methode Comparator.comparing erwartet ein Function-Objekt als Parameter:</p><p><code>Comparator<Song> nachTitel = Comparator.comparing(s -> s. getTitel());</code></p><p>In diesem Beispiel werden Songs nach ihrem Titel sortiert, indem jeder Song als einen String, sein Titel abbildet und anschliessend nach der natürlichen Reihenfolge dieser Strings sortiert wird. Genau in diesem Fall können Sie auch eine Methodenreferenz verwenden: (da der Lambda-Ausdruck lediglich aus einem parameterlosen Methodenaufruf besteht):</p><p><code>Comparator<Song> nachTitel = Comparator.comparing(Song::getTitel);</code></p><p>Es gibt aber auch Funktionen deren Eingabe- und Ausgabetypen identisch sind, diese werden als Unary-Operator bezeichnet. So gibt es zum Beispiel den IntUnaryOperator, der einen int-Wert auf einen anderen int-Wert abbildet.</p><h3 id="mcetoc_1g4tdtt405ph">Predicate</h3><p>Funktionen bei denen der Eingabewert immer auf eine boolean-Ausgabe abgebildet wird, werden Prädikate genannt. Predicate könnte also auch ToBooleanFunction heisst, hat aber wegen seiner besonderen Bedeutung einen eigenen Namen erhalten. Predicate sind besonders wichtig zum Filtern. Damit kann ein Stream mit einem Predicate-Objekt gefiltert werden, so dass nur noch die Elemente enthalten sind, die das Prädikat erfüllen, für die der Lambda-Ausdruck also true zurückgibt:</p><p><code>List<Song> songs = …;</code><br><code>songs.stream().filter(s -> s. getSterne() == 5).count();</code></p><p>Doch damit nicht genug, es ist weiter möglich Predicate mit logischen Operatoren AND, OR und NOT anzuwenden und somit mehrere Predicate zu einem einzigen zu verknüpfen:</p><p><code>private static Predicate<Song> baueSuchPredicate(String suchtitel,</code><br><code> String suchinterpret, int suchsterne) {</code><br><code> Predicate<Song> filter = (s->true);</code><br><code> if (suchtitel != null){</code><br><code> filter = filter.and(s -> </code><br><code> s.getTitel().startsWith(suchtitel));</code><br><code> }</code><br><code> if (suchinterpret != null){</code><br><code> filter = filter.and(s -> </code><br><code> s.getInterpret().startsWith(suchinterpret));</code><br><code> }</code></p><p><code></code><code> if (suchsterne > 0){</code><br><code> filter = filter.and(s -> s. getSterne() >= suchsterne);</code><br><code> }</code><br><code> return filter;</code><br><code>}</code></p><p>Die Initialisierung mit Predicate<Song> filter = (s->true) wird deshalb so vorgenommen, damit es ein erstes Objekt gibt, an dem Sie überhaupt and rufen können. Anderenfalls müssten Sie bei jedem Suchattribut wieder prüfen, ob es schon einen Filter gibt, falls ja, and rufen, und falls nein, einen erzeugen.</p><h3 id="mcetoc_1g4tdtt405pi">Consumer</h3><p>Dabei handelt es sich um Funktionen ohne Rückgabewert. Sie erwarten einen Parameter, den sie verarbeiten, liefern aber kein Ergebnis:</p><p><code>public static void main(String[] args) throws IOException{</code><br><code> liesStrings((s) -> System.out.println(s));</code><br><code>}</code><br><code> </code><br><code>public static void liesStrings(Consumer<String> sink) throws IOException{</code><br><code> BufferedReader in = new BufferedReader(new InputStreamReader(System.in));</code><br><code> String line;</code><br><code> while (!"".equals(line = in.readLine())){</code><br><code> sink.accept(line);</code><br><code> }</code><br><code>}</code></p><p>Die Methode liesStrings liest so lange beliebig viele Strings von der Standardeingabe, bis eine leere Zeile gelesen wird und gibt jede gelesene teile an den übergebenen Consumer<String> weiter. Im Beispiel werden die gelesenen Strings einfach wieder ausgegeben, aber dieselbe Methode könnte eine Eingabe auch in einer Liste sammeln, oder jede Zeile als Kommando interpretieren:</p><p><code>//Zeilen in eine Liste lesen</code><br><code>List<String> zeilen = new ArrayList<>();</code><br><code>liesStrings(zeilen::add);</code><br><code>//Zeilen als Kommandos ausführen</code><br><code>liesStrings(this::fuehreKommandoAus);</code></p><h3 id="mcetoc_1g4tdtt405pj">Supplier</h3><p>Supplier ist das Gegenstück zum Consumer, sie haben keine Parameter, geben aber etwas zurück.</p><p>Welchen Sinn kann ein solcher Aufruf</p><p><code>zeigeNachricht(() -> entschluessleNachricht(nachricht))</code><br><br>gegenüber dem folgenden, einfacheren haben?<br><br><code>zeigeNachricht(entschluessleNachricht(nachricht))</code><br><br>In diesem Beispiel können Sie unnötigen Rechenaufwand vermeiden. Die Methode zeigeNachricht stammt aus einem fiktiven E-Mail-Client, der Verschlüsselung beherrscht. Ihre Implementierung könnte so aussehen:<br><br><code>public zeigeNachricht(String nachricht){</code><br><code> if (zeigeVorschau)</code><br><code> System.out.println(nachricht);</code><br><code>}</code></p><p>Im Beispiel wird die entschlüsselte Nachricht an die Methode übergeben, obwohl noch nicht klar ist, ob sie überhaupt benötigt wird. Wenn zeigeVorschau false ist, dann wird der Parameter ignoriert und die potenziell teure Entschlüsselung war umsonst.</p><p><code>public zeigeNachricht(Supplier<String> nachricht){</code><br><code> if (zeigeVorschau)</code><br><code> System.out.println(nachricht.get());</code><br><code>}</code></p><p>Nicht so in diesem Fall. Die Nachricht wird erst dann entschlüsselt, wenn am Supplier get gerufen wird, solange get nicht gerufen wird, wird die Nachricht nicht entschlüsselt.</p><h3 id="mcetoc_1g4tdtt405pk">BiFunction, BiPredicate, BiConsumer</h3><p>Zu diesen Funktionen gibt es jeweils noch eine Variante mit einem vorangestellten Bi-. Diese unterscheiden sich von ihren einfachen Gegenstücken dadurch, dass sie zwei Parameter statt einem nehmen. Ein BiPredicate bildet also zum Beispiel zwei Objekte auf einen boolean-Wert ab. Funktionen die zwei gleichartige Wert auf einen dritten Wert desselben Typs abbilden heissen BinaryOperator.</p></div><footer class="wrapper post__footer"><p class="post__last-updated">This article was updated on Juni 20, 2022</p><ul class="post__tag"><li><a href="https://www.finecloud.ch/tags/java/">java</a></li><li><a href="https://www.finecloud.ch/tags/lambda/">lambda</a></li><li><a href="https://www.finecloud.ch/tags/softwareentwicklung/">software development</a></li></ul><div class="post__share"></div></footer></article></main><footer class="footer"><div class="footer__copyright"><p>Powered by Publii</p></div><button onclick="backToTopFunction()" id="backToTop" class="footer__bttop" aria-label="Back to top" title="Back to top"><svg><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#toparrow"/></svg></button></footer></div><script>window.publiiThemeMenuConfig = {
mobileMenuMode: 'sidebar',
animationSpeed: 300,
submenuWidth: 'auto',
doubleClickTime: 500,
mobileMenuExpandableSubmenus: true,
relatedContainerForOverlayMenuSelector: '.top',
};</script><script defer="defer" src="https://www.finecloud.ch/assets/js/scripts.min.js?v=6ca8b60e6534a3888de1205e82df8528"></script><script>var images = document.querySelectorAll('img[loading]');
for (var i = 0; i < images.length; i++) {
if (images[i].complete) {
images[i].classList.add('is-loaded');
} else {
images[i].addEventListener('load', function () {
this.classList.add('is-loaded');
}, false);
}
}</script><script defer="defer" src="https://www.finecloud.ch/media/plugins/syntaxHighlighter/prism.js"></script></body></html>