-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstreamcollect-daten-aus-einem-stream-sammeln.html
18 lines (17 loc) · 13 KB
/
streamcollect-daten-aus-einem-stream-sammeln.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>Stream.collect - Daten aus einem Stream sammeln - Finecloud</title><meta name="description" content="Die mächtige collect-Methode ist mit zwei Signaturen überladen, collect(Supplier, BiConsumer, BiConsumer) und collect(Collector). Beide sind aber prinzipiell identisch; ein Collection ist lediglich ein Objekt, das die drei Funktionen zusammenfasst und wiederverwendbar macht. collect sieht etwas bedrohlich aus, weil man gleich drei Funktionen übergeben muss, die…"><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/streamcollect-daten-aus-einem-stream-sammeln.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="Stream.collect - Daten aus einem Stream sammeln"><meta property="og:site_name" content="Finecloud"><meta property="og:description" content="Die mächtige collect-Methode ist mit zwei Signaturen überladen, collect(Supplier, BiConsumer, BiConsumer) und collect(Collector). Beide sind aber prinzipiell identisch; ein Collection ist lediglich ein Objekt, das die drei Funktionen zusammenfasst und wiederverwendbar macht. collect sieht etwas bedrohlich aus, weil man gleich drei Funktionen übergeben muss, die…"><meta property="og:url" content="https://www.finecloud.ch/streamcollect-daten-aus-einem-stream-sammeln.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/streamcollect-daten-aus-einem-stream-sammeln.html"},"headline":"Stream.collect - Daten aus einem Stream sammeln","datePublished":"2022-06-02T20:34","dateModified":"2022-06-20T07:10","description":"Die mächtige collect-Methode ist mit zwei Signaturen überladen, collect(Supplier, BiConsumer, BiConsumer) und collect(Collector). Beide sind aber prinzipiell identisch; ein Collection ist lediglich ein Objekt, das die drei Funktionen zusammenfasst und wiederverwendbar macht. collect sieht etwas bedrohlich aus, weil man gleich drei Funktionen übergeben muss, die…","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-06-02T20:34">Juni 2, 2022</time></div><h1>Stream.collect - Daten aus einem Stream sammeln</h1></div></header></div><div class="wrapper post__entry"><p>Die mächtige collect-Methode ist mit zwei Signaturen überladen, collect(Supplier, BiConsumer, BiConsumer) und collect(Collector). Beide sind aber prinzipiell identisch; ein Collection ist lediglich ein Objekt, das die drei Funktionen zusammenfasst und wiederverwendbar macht.</p><p>collect sieht etwas bedrohlich aus, weil man gleich drei Funktionen übergeben muss, die zusammen irgendwie Ihre Ausgabe erzeugen sollen. Jede Funktion hat eine klar definierte Aufgabe:</p><ul><li>Der <strong>Supplier</strong> erzeugt ein Objekt, in dem gesammelt werden soll. Wenn man mittels collection eine Liste aus einem Stream erzeugen will, dann muss der Supplier diese Liste erzeugen. Warum übergibt man dann nicht gleich das Objekt, in dem gesammelt werden soll? Weil der Supplier in einem parallelen Stream mehrmals gerufen wird: Es werden mehrere Listen erzeugt, die später zusammengefasst werden.</li><li>Die <strong>erste BiConsumer</strong>, genannt der <em>Akkumulator</em>, kombiniert ein Element des Streams mit einem der vom Supplier erzeugten Sammelobjekte. Um beim Beispiel der Liste zu bleiben, fügt diese Funktion der Liste ein Element hinzu.</li><li>Der <strong>zweite BiConsumer</strong>, der <em>Kombinator</em>, fügt zwei Sammelobjekte zu einem zusammen. Diese Funktion sorgt also dafür, dass am Ende nur eine Liste zurückgegeben wird, auch wenn mehrere vom Supplier erzeugt wurden. Damit das funktioniert, muss das Sammelobjekt eine Funktion haben, dir diesem Objekt den Inhalt eines anderen Objekts hinzufügt, wie zum Beispiel die Methode addAll an einer Liste.</li></ul><p>Das Beispiel zeigt, wie alle Stream-Elemente in einer Liste gesammelt werden können:</p><p><code>List<Person> personen = personenStream.collect(</code><br><code> ArrayList::new, </code><br><code> ArrayList::add, </code><br><code> ArrayList::addAll);</code></p><p>collect funktioniert nicht nur mit Listen, auch wenn der Methodenname nach Collections klingt. Jedes Objekt, das geeignete Methoden bereitstellt, kann zum Sammeln verwendet werden. So sammeln Sie alle Titel aus Ihrer Musiksammlung in einem String:</p><p><code>String songliste = songs.collect(StringBuilder::new, </code><br><code> (acc, el) -> acc.append(el.getTitel()).append("\n"), </code><br><code> StringBuilder::append).toString();</code></p><p>Die drei richtigen Funktionen für einen Collector anzugeben, kann schwierig sein. Als Hilfe können die statische Methoden der Companion-Klasse verwendet werden, die nützliche Kollektoren bereitstellt. Zum Beispiel die, welche aus einem Stream wieder eine Collection machen:</p><p><code>List<Song> songList = songs.collect(Collectors.toList());</code><br><code>Set<Song> songSet = songs.collect(Collectors.toSet());</code></p><p>Kollektoren können mehr als das, die nachfolgenden Möglichkeiten aus Collectors machen deutlich, wie mächtig die collect-Methode ist:</p><table style="border-collapse: collapse; width: 100%;" border="1"><tbody><tr><td style="width: 49.9288%;"><strong>collectors-Methode</strong></td><td style="width: 49.9288%;"><strong>Funktion</strong></td></tr><tr><td style="width: 49.9288%;">mapToDouble().average()</td><td style="width: 49.9288%;">Durchschnitt berechnen</td></tr><tr><td style="width: 49.9288%;">.count()</td><td style="width: 49.9288%;">Elemente zählen</td></tr><tr><td style="width: 49.9288%;">.summarizingDouble</td><td style="width: 49.9288%;">Statistische Daten, Summe (Double)</td></tr><tr><td style="width: 49.9288%;">.summarizingInt</td><td style="width: 49.9288%;">Statistische Daten, Summe (Int)</td></tr><tr><td style="width: 49.9288%;">.summarizingLong</td><td style="width: 49.9288%;">Statistische Daten, Summe (Long)</td></tr></tbody></table><p><code>DoubleSummaryStatistics statistik = zeilen</code><br><code> .flatMap(line -> Arrays.stream(line.split("\\s+"))</code><br><code> .skip(1))</code><br><code> .collect(Collectors.summarizingDouble(Double::parseDouble));</code><br><code> System.out.println("Kältester Monat: " + statistik.getMin() + " Grad.");</code><br><code> System.out.println("Wärmster Monat: " + statistik.getMax() + " Grad.");</code><br><code> System.out.println("Durchschnitt: " + statistik.getAverage() + " Grad.");</code></p><p>Für fortgeschrittene statistische Auswertungen reicht das zwar noch nicht, es fehlt zum Beispiel eine Varianz, aber wenn Sie diese Funktionalität benötigen, können Sie nach demselben Muster einen eigenen Kollektor schreiben.</p><p>Die wohl vielseitigsten collect-Operationen, die Collectors anbietet, sind Partitionierung und Gruppierung. Beide trennen die Elemente im Stream nach einem festgelegten Kriterium in mehrere Gruppen. Der Unterschied zwischen den beiden besteht nur darin, dass <em>partitioningBy</em> Elemente nach einem Prädikat in zwei Gruppen zerlegt, die true-Gruppe und die false-Gruppe, während <em>groupingBy</em> anhand einer Funktion beliebig viele Gruppen erzeugen kann, eine für jeden Wert, den die Funktion zurückgegeben hat. Beide geben eine Map zurück, in der die Schlüssel TRUE/FALSE oder die Rückgabewerte der Funktion enthalten sind, mit den Werten dazu als jeweils eine Liste aller Objekte, die in diese Gruppe sortiert wurden. Mit diesem Beispiel können Songs nach Interpret sortiert werden:</p><p><code>songs.collect(Collectors.groupingBy(Song::getInterpret));</code></p><p>Dieses Beispiel gibt eine Map zurück, deren Schlüssel die Namen der Interpreten sind, die dazugehörigen Werte sind Listen aller Songs dieses Interpreten. Wenn Sie noch einen Schritt weiter gehen wollen, können Sie <em>groupingBy</em> und <em>partitioningBy</em> einen weiteren Collector übergeben, der auf die Werte jeder Gruppe angewendet wird:</p><p><code>songs.collect(Collectors.groupingBy(</code><br><code> Song::getInterpret,</code><br><code> Collectors.maxBy(Comparator.comparing(Song::getSterne))));</code></p><p>So einfach bekommen Sie den besten Song jedes Interpreten. Erst werden Songs nach Interpret gruppiert, in jeder Gruppe wird anschliessend der Song mit der maximalen Anzahl Sterne gefunden.</p><p>Fast immer ist es egal, welche Art von Map Sie beim Gruppieren oder Partitionieren zurückbekommen, aber in seltenen Fällen möchten Sie eine bestimmte Art von Map nutzen, zum Beispiel eine SortedMap. Für diesen Fall können Sie auch noch einen Supplier übergeben, der die richtige Map-Implementierung erzeugt.</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>