-
Notifications
You must be signed in to change notification settings - Fork 0
/
die-stream-api.html
18 lines (17 loc) · 25.3 KB
/
die-stream-api.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>Die Stream-API - Finecloud</title><meta name="description" content="Das konsequente Fluent Interface der Stream-API macht es möglich, mit einem Blick zu erkennen was durch einen Lambda-Ausdruck in jeder einzelnen Zeile geschieht. Mit diesem Beispiel werden alle Vielfachen von 3 zwischen 0 und 100 ausgegeben: IntStream.range(0, 100) .filter(i -> i % 3 == 0)…"><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/die-stream-api.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="Die Stream-API"><meta property="og:site_name" content="Finecloud"><meta property="og:description" content="Das konsequente Fluent Interface der Stream-API macht es möglich, mit einem Blick zu erkennen was durch einen Lambda-Ausdruck in jeder einzelnen Zeile geschieht. Mit diesem Beispiel werden alle Vielfachen von 3 zwischen 0 und 100 ausgegeben: IntStream.range(0, 100) .filter(i -> i % 3 == 0)…"><meta property="og:url" content="https://www.finecloud.ch/die-stream-api.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/die-stream-api.html"},"headline":"Die Stream-API","datePublished":"2022-05-31T09:54","dateModified":"2022-06-20T07:10","description":"Das konsequente Fluent Interface der Stream-API macht es möglich, mit einem Blick zu erkennen was durch einen Lambda-Ausdruck in jeder einzelnen Zeile geschieht. Mit diesem Beispiel werden alle Vielfachen von 3 zwischen 0 und 100 ausgegeben: IntStream.range(0, 100) .filter(i -> i % 3 == 0)…","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-31T09:54">Mai 31, 2022</time></div><h1>Die Stream-API</h1></div></header></div><div class="wrapper post__entry"><div class="post__toc"><h3>Table of Contents</h3><ul><li><a href="#mcetoc_1g4tdrc035oj">Intermediäre und terminale Methoden</a></li><li><a href="#mcetoc_1g4tdrc035ok">Intermediäre Operatoren</a><ul><li><a href="#mcetoc_1g4tdrc035ol">Sortieren (sort)</a></li><li><a href="#mcetoc_1g4tdrc035om">Limitieren (limit)</a></li><li><a href="#mcetoc_1g4tdrc035on">Überspringen (skip)</a></li><li><a href="#mcetoc_1g4tdrc035oo">Filtern (filter)</a></li><li><a href="#mcetoc_1g4tdrc035op">Einmaligkeit (distinct)</a></li><li><a href="#mcetoc_1g4tdrc035oq">Abbilden</a></li><li><a href="#mcetoc_1g4tdrc035or">Spicken (peek)</a></li></ul></li><li><a href="#mcetoc_1g4tdrc035os">Terminale Operatoren</a><ul><li><a href="#mcetoc_1g4tdrc035ot">Alle Elemente verarbeiten</a></li><li><a href="#mcetoc_1g4tdrc035ou">Finden</a></li><li><a href="#mcetoc_1g4tdrc035ov">Prüfen</a></li><li><a href="#mcetoc_1g4tdrc035p0">Reduzieren</a></li></ul></li></ul></div><p>Das konsequente Fluent Interface der Stream-API macht es möglich, mit einem Blick zu erkennen was durch einen Lambda-Ausdruck in jeder einzelnen Zeile geschieht. Mit diesem Beispiel werden alle Vielfachen von 3 zwischen 0 und 100 ausgegeben:</p><p><code>IntStream.range(0, 100)</code><br><code> .filter(i -> i % 3 == 0)</code><br><code> .forEach(System.out::println);</code></p><p>Richtig praktisch werden solche Lambda und Streams beim lesen von Dateiinhalten:</p><p><code>BufferedReader danksagung = new BufferedReader(new FileReader("ebook.txt"))</code><br><code>danksagung.lines()</code><br><code> .filter(line -> line.toLowerCase().contains("Danksagung"))</code><br><code> .findFirst()</code><br><code> .ifPresent(System.out::println);</code></p><p>Ab welcher Zeile startet im E-Book die Danksagung? Mit findFrist wird nur die erste Zeile gesucht, in der ein Ergebnis steht, anschliessend wird nicht mehr weiter gesucht, sondern das Ergebnis wird ausgegeben.</p><p>Streams sind eine andere Art in Java mit Listen von Daten umzugehen, aber sie sind keinen Ersatz für Collections oder Arrays, eher eine Ergänzung. Streams fehlt nämlich eine Eigenschaft, welche den anderen Datenstrukturen haben: Permanenz. In einer Collection speichern Sie Daten, um bei Bedarf wieder darauf zuzugreifen und zwar so oft sie wollen. Ein Stream dient lediglich der Verarbeitung von Daten. Sie können den Inhalt einen Streams genau einmal auslesen, danach ist er weg und nicht mehr zurückzubekommen. Insofern gleicht ein Stream eher einem Iterator als einer Collection. Wenn Sie auf die Ausgabe der Pipeline nach Belieben wieder zugreifen möchten, dann müssen Sie sie wieder in einer Collection sammeln.</p><h3 id="mcetoc_1g4tdrc035oj">Intermediäre und terminale Methoden</h3><p>Der Unterschied ist, das Intermediäre Methoden wieder ein Stream zurückgeben mit dem man weiterarbeiten kann, terminale Methoden geben einen anderen Ergebnistyp zurück. So entsteht eine Pipeline, die durch die terminale Methode gesteuert wird. Sie "zieht" Daten aus dem Stream und erst durch die terminale Methode werden überhaupt Daten aus dem Stream gelesen. Solange Sie nur intermediäre Methoden aufrufen, passiert im Stream noch nichts.</p><p><em>findFrist</em> gibt keinen Stream mehr zurück, sondern ein Optional und if-Present ist eine Methode davon. <em>findFirst</em> ist eine terminale Methode, also eine die am Ende der Stream-Verarbeitung steht. <em>filter</em> dagegen ist eine intermediäre Methode und steht in der Mitte der "Pipeline".</p><p>Schauen wir uns das mit dem Beispiel von oben an:</p><ul><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Die Methode BufferedReader.lines erzeugt einen Stream<String>. Es werden noch keine Daten gelesen.</span></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Aus diesem Stream wird mit filter ein neuer Stream erzeugt, der die Filteranweisung verarbeitet. Es werden noch immer keine Daten gelesen.</span></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Die terminale Methode findFirst wird gerufen. Nun beginnt die Verarbeitung.</span></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">findFirst liest das erste Element aus dem gefilterten Stream.</span></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Der gefilterte Stream liest das erste Element des ungefilterten Streams und wertet sein Prädikat line.toLowerCase().contains("Danksagung") aus.</span></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Die erste Zeile "Einleitung" wird vom Filter zurückgewiesen. Der gefilterte Stream liest die zweite Zeile des ungefilterten Streams und wendet erneut sein Prädikat an. Auch diese Zeile wird zurückgewiesen.</span></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Erst Zeile Nummer X wird vom Filter akzeptiert. Jetzt gibt der gefilterte Stream seine erste Rückgabe: "Danksagung".</span></li><li>findFirst empfängt die Rückgabe vom gefilterten Stream. Es benötigt keine weiteren Ergebnisse. Es wird nur der erste Treffer gesucht, deshalb wird kein weiteres Element aus dem gefilterten Stream gelesen.</li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">findFirst schliesst den gefilterten Stream und gibt das gefundene Ergebnis (richtiger: ein Optional mit dem gefundenen Ergebnis) zurück.</span></li><li><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Was ist wirklich passiert? Es wurden 13 Zeilen aus dem ungefilterten Stream gelesen, davon wurde eine Zeile in den gefilterten Stream weitergeschrieben. Mehr nicht.</span></li></ul><p>Damit wurde keine Zeile mehr gelesen, als notwendig. Streams sind nicht nur gut darin, Ihre Absichten in Code auszudrücken, sie sind dabei auch noch äusserst effizient.</p><h3 id="mcetoc_1g4tdrc035ok">Intermediäre Operatoren</h3><h4 id="mcetoc_1g4tdrc035ol"><strong>Sortieren (sort)</strong></h4><p>Einen Stream kann nach seiner natürlichen Ordnung sortiert werden, wenn seine Elemente Comparable implementieren, oder mit einem übergebenen Comparator. In allen Fällen bleibt der Inhalt der Datenquelle unverändert. Nachfolgend ein Beispiel, darin wird der heisseste Tag im Jahr gesucht, zuerst wird absteigend nach Temperatur sortiert und dann das erste Element selektiert:</p><p><code>tagestemperaturen</code><br><code> .sorted(Comparator</code><br><code> .comparing(Tagestemperatur::getTemperatur)</code><br><code> .reversed())</code><br><code> .findFirst();</code></p><h4 id="mcetoc_1g4tdrc035om">Limitieren (limit)</h4><p>Meistens will man nur auf einem teil des Streams arbeiten, z.B. nur auf dem Anfang. Mit limit kann ein Stream auf eine beliebige Anzahl von Elementen beschränkt werden. Auch wenn der darunterliegende Stream mehr Elemente hätte, endet der limitierte Stream, wenn seine Anzahl erreicht ist. Im Beispiel werden die zehn besten Songs aus einer Sammlung sortiert, limitiert und ausgegeben:</p><p><code>songs</code><br><code> .sorted(Comparator.comparing(Song::getSterne).reversed())</code><br><code> .limit(10)</code><br><code> .forEach(song -> System.out.println(song.getTitel()));</code></p><h4 id="mcetoc_1g4tdrc035on">Überspringen (skip)</h4><p>Will man nicht nach einem bestimmen Inhalt suchen, sondern diesen bestimmten Inhalt bewusst überspringen. Folgende Datei soll eingelesen werden:</p><p><em>Höchsttemperaturen Basel</em><br><em>Datum;Temperatur</em><br><em>01.3.2021;1</em><br><em>02.3.2021;3</em><br><em>13.3.2021;8</em><br><em>…</em></p><p>dabei interessieren uns aber nur die Temperaturen, die ersten zwei Zeilen interessieren uns nicht:</p><p><code>daten.lines()</code><br><code> .skip(2)</code><br><code> .map(TemperaturMessung::parse)</code><br><code> ...</code></p><h4 id="mcetoc_1g4tdrc035oo">Filtern (filter)</h4><p>Man übergibt ihr ein Predicate und nur die Elemente, für die das Predicate true liefert, werden im Stream weitergereicht:</p><p><code>kandidaten</code><br><code> .filter(k -> k.getHaarfarbe().equals("rot") </code><br><code> && k.getAugenfarbe().equals("grün"))</code><br><code> .forEach(k -> sprichAn(k));</code></p><h4 id="mcetoc_1g4tdrc035op">Einmaligkeit (distinct)</h4><p>Wenn in einem Stream Duplikate entfernt werden sollen, kann das mit distinct sichergestellt werden. Damit merkt sich der Strom alle Elemente, die bereits einmal vorkamen und gibt sie kein zweites Mal zurück. Bei Streams von Objekten wird Gleichheit mit equals bestimmt. Achtung: distinct ist eine Operation mit Zustand und kann für lange Streams sehr viel Speicher belegen.</p><p><code>kontakte</code><br><code> .distinct()</code><br><code> .count();</code></p><h4 id="mcetoc_1g4tdrc035oq">Abbilden</h4><p>Das sind alle Operationen, die aus den Eingabewerten etwas berechnen und als Ausgabestrom wieder ausgeben:</p><p><code>personen</code><br><code> .map(Person::getName)</code><br><code> .forEach(System.out::println);</code></p><p>Mit der map-Methode ist der Ausgabe-Stream wieder ein Stream von Objekten; wenn das Ergebnis der Function ein primitiver Typ ist, wird er dazu in den passenden Wrapper konvertiert. Wenn man deinen Stream von primitiven Typen als Ausgaben benötigt, stehen dafür die Methoden <em>mapToInt</em>, <em>mapToLong</em> und <em>mapToDouble</em> zur Verfügung.</p><p>Etwas komplizierter ist die Methode flatMap und ihre primitiven Gegenstücke. Sie erwarten als Parameter eine Funktion, die aus jedem Eingabeelement einen Stream erzeugt. Die Ausgabe von flatMap ist ein Stream, in dem die Elemente aller Streams jeweils nacheinander zu einem Ausgabe Stream zusammengefasst sind. Als Beispiel: Das Stadtfest in Ihrer Stadt. Es war eine Anmeldung erforderlich und von jeder Anmeldung wird erwartet, dass die gesamte Familie mitkommt. Anmeldungen sind in einem Objekt vom typ Person gespeichert, das den Namen der Person enthält, seinen oder ihren Partner als weiteres Person-Objekt und die Kinder als Liste von Personen. Angemeldet sind:</p><ul><li>Hans Fischer mit Partner Frieda Fischer und den Kindern Fritz, Max und Lisa</li><li>Ida mit Partner Martin</li><li>Max Müller mit seinen Kindern Moritz und Peter</li></ul><p>Von der ersten Anmeldung ausgehend soll nun eine Liste aller erwarteten Gäste ausgegeben werden:</p><p><code>anmeldungen</code><br><code> .flatMap(p -> Stream.concat(</code><br><code> Stream.of(p, p.getPartner()), </code><br><code> p.getKinder().stream()))</code><br><code> .filter(p -> p != null)</code><br><code> .map(Person::getName)</code><br><code> .forEach(System.out::println);</code></p><p>Mit flatMap ist die Liste schnell erstellt, aber was genau passiert, ist auch mit Lambda-Ausdrücken nicht sofort ersichtlich:</p><ul><li>Mit Stream.of wird ein Stream erzeugt, der die person selbst und ihren Partner enthält. Dank Varargs können Stream.of einfach alle Elemente übergeben werden, die der so erzeugt Stream enthalten soll.</li><li>Aus der Liste von Kindern wird ein weiterer Stream erzeugt. Da die Kinder in einer Collection gespeichert sind, kann da smit der stream-Methode erreicht werden.</li><li>Diese beiden Stream werden mit Stream.concat zusammengesetzt. Die Methode gibt einen Stream zurück, der das Erste aller Elemente des ersten übergebenen Streams und danach allen Elemente des zweiten übergebenen Streams enthält.</li><li>flatMap wird für jede Person aus <em>anmeldungen</em> gerufen, intern werden dadurch drei Stream erzeugt: [Hans Fischer, Frieda Fischer, Fritz, Max, Lisa][Ida, Martin][Max Müller, null, Moritz und Peter]. Da Max Müller keinen Partner (mehr) hat, resultiert aus p.getPartner() ein null-Wert; dieser wird von der späteren filter-Anweisung wieder entfernt werden.</li><li>flatMap gibt aber nicht einen Stream pro Eingabe zurück (das käme bei map heraus), sondern nur einen langen Stream. Daher auch der Name flatMap: Anstatt einen Stream von Streams auszugeben, ist die Ausgabe flach. Der so erzeugte Stream enthält also: [Hans Fischer, Frieda Fischer, Fritz, Max, Lisa, Ida, Martin, Max Müller, null, Moritz und Peter]</li></ul><h4 id="mcetoc_1g4tdrc035or">Spicken (peek)</h4><p>peek gibt genau denselben Stream aus, der auch eingegeben wurde, führt aber für jedes Element einen Consumer aus. Der Inhalt des Streams wird nicht verändert. Mit peek können Sie einem Stream bei der Arbeit zuschauen, was insbesondere bei Fehlersuche hilfreich ist:</p><p><code>danksagung.lines()</code><br><code> .peek(line -> System.out.println("Ungefiltert " + line))</code><br><code> .filter(line -> line.toLowerCase().contains("Danksagung"))</code><br><code> .peek(line -> System.out.println("Gefiltert " + line))</code><br><code> .findFirst()</code><br><code> .ifPresent(System.out::println);</code></p><p>peek kann auch verwendet werden, um beispielsweise bei Anmeldungen Bestätigungen zu versenden:</p><p><code>anmeldungen</code><br><code> .peek(p -> bestaetigeAnmeldung(p))</code><br><code> .flatMap(p -> Stream.concat(Stream.of(</code><br><code> p, p.getPartner()), </code><br><code> p.getKinder().stream()))</code><br><code> .filter(p -> p!= null)</code><br><code> .map(Person::getName)</code><br><code> .forEach(System.out::println);</code></p><h3 id="mcetoc_1g4tdrc035os">Terminale Operatoren</h3><h4 id="mcetoc_1g4tdrc035ot">Alle Elemente verarbeiten</h4><p>Diese Methode führt für alle Elemente, die am Ende in einem Stream enthalten sind, diesele Operation aus. forEach ist als Beispiel zu nennen. Sie führt den übergebenen Consumer für jedes Element des Streams aus. </p><h4 id="mcetoc_1g4tdrc035ou">Finden</h4><p>Wenn aus einem Stream nicht alle Elemente verarbeitet werden solle, sondern nur ein einzelnen benötigt wird, gibt es dafür findFirst oder findAny:</p><p><code>Optional<Student> gut = studenten</code><br><code> .filter(student -> student.getNotendurchschnitt() == 5.0)</code><br><code> .findAny();</code></p><p>Der unterschied zwischen den beiden Methoden ist, dass findFirst garantiert das erste Element zurückgibt, findAny nur irgendein Element. Dieser Unterschied kommt bei paralleler Verarbeitung zum Tragen, wo das erste gefunden Element nicht notwendig das erste aus dem Stream ist. findFirst stellt in dieser Situation sicher, dass wirklich das erste Element des Stream ausgegeben wird.</p><p>Beide Methoden geben ein Optional-Objekt zurück. Grob gesagt handelt es sich um einen Umschlag, der ein Objekt ungleich null enthalten oder auch leer sein kann. So wird auch, wenn kein Ergebnis gefunden wurde, ein Objekt zurückgegeben, nicht direkt ein null-Wert. Dadurch können Sie an dem zurückgegeben en Objekt immer weitere Methoden aufrufen und müssen nicht auf null prüfen, was. in der Aufrufkette der Fluent API nicht möglich wäre. Stattdessen können Sie diese Prüfung in die Aufrufkette integrieren:</p><p><code>studenten</code><br><code> .filter(student -> student.getNotendurchschnitt() == 5.0)</code><br><code> .findAny()</code><br><code> .ifPresent(s -> verarbeiteGutenStudenten(s));</code></p><p>Das an ifPresent übergebene Lambda wird nur ausgeführt, wenn das von findAny zurückgegebene Optional ein Ergebnis enthält.</p><h4 id="mcetoc_1g4tdrc035ov">Prüfen</h4><p>Nur um zu prüfen, ob der Stream Elemente enthält, die einem bestimmten Kriterium entsprechen, ohne diese Elemente zurückzugeben, gibt es drei boolesche Methoden. anyMatch, prüft, ob irgendein Element des Streams zum übergebenen Predicate passt, allMatch prüft, ob alle Elemente passen, und noneMatch schliesslich, ob keines der Elemente passt.</p><p><code>if (studenten.anyMatch(student -> </code><br><code> student.getNotendurchschnitt() == 6.0)){</code><br><code> … </code><br><code>}</code></p><h4 id="mcetoc_1g4tdrc035p0">Reduzieren</h4><p>Mit Streams können Sie auch einen einzelnen Wert berechnen lassen, der den Stream zusammenfasst. Der Inhalt wird auf diesen einen Wert reduziert, daher auch der Name der Methode für diese Operatoren: reduce.</p><p><code>int gesamtlaenge = songs</code><br><code> .mapToInt(Song::getLaengeInSekunden)</code><br><code> .reduce(0, (x, y) -> x+y);</code></p><p>Die reduce-Methode funktioniert, indem nacheinander (oder sogar parallel) alle Elemente des Streams durch die übergebene Funktion mit einem Akkumulator verknüpft werden. Der Akkumulator wird mit dem übergebenen Neutralwert der Verknüpfung vorbelegt. Im Beispiel werden also, von einem Wert 0 ausgehend, die Länge aller Songs im Stream addiert, um die Gesamtlänge zu berechnen.</p><p>Sie müssen keinen Neutralwert übergeben, dann erhält der Akkumulator anfangs das erste Element (sofern vorhanden)m due erste Verknüpfung geschieht mit dem zweiten Element, und das Ergebnis der reduce-Operation ist Optional. Im Beispiel soll der längste Songs gefunden werden:</p><p><code>Optional<Song> laengsterSong = songs.reduce((x, y) -></code><br><code> x.getLaengeInSekunden() > y.getLaengeInSekunden() ? x : y);</code></p><p>Der ternäre Fragezeichen-Operator gibt immer den längeren der beiden Songs zurück, am Ende bleibt im Akkumulator der längste stehen.</p><p>Einige häufigt reduce-Operatoren sind schon als eigene Methoden implementiert:</p><table style="border-collapse: collapse; width: 100%;" border="1"><tbody><tr><td style="width: 49.9288%;"><strong>Methode</strong></td><td style="width: 49.9288%;"><strong>Funktion</strong></td></tr><tr><td style="width: 49.9288%;">count</td><td style="width: 49.9288%;">zählt die Elemente im Stream</td></tr><tr><td style="width: 49.9288%;">(nur primitive Streams) sum</td><td style="width: 49.9288%;">summiert alle Zahlen im Stream</td></tr><tr><td style="width: 49.9288%;">(nur primitive Streams) min / max</td><td style="width: 49.9288%;">das kleinste, bzw. grösste Element</td></tr><tr><td style="width: 49.9288%;">(nur primitive Streams) average</td><td style="width: 49.9288%;">Durchschnitt aller Elemente</td></tr></tbody></table><p>Komplexere Methoden, die aus einem Stream wieder andere Typen gewinnen, um z.B. einen Stream wieder in eine Liste umzuwandeln, werden mit Collections umgesetzt.</p><p> </p><p> </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><li><a href="https://www.finecloud.ch/tags/stream-api/">stream-api</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>