Java 8 – Stream API

Kommen wir nun im dritten Artikel zu den etwas spannenderen und vielleicht nicht ganz so theoretischen und ersten Annäherungen, die Java8 (oder 1.8) an Neuheiten mit sich bringt – die Stream API.

Das Beispiel aus dem Artikel zu Functional Interfaces wird hierbei als Grundlage verwendet ist aber natürlich als eigenes Package java_8_class_3 im Github-Repository zu finden. Kurz zusammengefasst wird hier die neue forEach-Methode des Iterable Interfaces genutzt, um über alle Elemente der Liste zu iterieren. Statt direkt auf der Liste zu iterieren, werden wir uns im ersten Schritt einen Stream erzeugen und diesen ausgeben:

Auch wenn uns der Optimizer darauf hinweist, dass wir den Ausdruck durch Verwendung der Collections.forEach-Methode vereinfachen können, ist unser Code lauffähig und erzeugt für diese Anweisung folgende Ausgabe:

Dass dieses Beispiel nicht sinnvoll ist – klar und dass die Verwendung von Stream hier nicht notwendig ist, ist auch klar, aber werfen wir einen Blick auf folgendes Beispiel:

Folgende Ausgabe erscheint:

Wir filtern also alle Strings, deren Werte kleiner als 4 sind. Nur der Vollständigkeit halber, können wir dieses Statement auch so schreiben:

Das ganze ist nicht nur deutlich unübersichtlicher und länger, sondern ist auch in der eigentlichen Entwicklung deutlich unangenehmer.

Um den Umgang mit der Stream API zu beherrschen sollten einige Dinge bekannt sein, ohne die es wenig Spaß macht, diese zu verwenden. Beginnen wir mit drei verschiedenen Operationskategorien, die auf Streams angewendet werden können:

  1. Create-Operationen:
    • meineListe.stream() –> sequentiell verarbeiteter Stream auf Basis einer Collection
    • meineListe.parallelStream() –> parallel verarbeiteter Stream auf Basis einerCollection
    • Arrays.stream(meinArray)[.parallel()] –> sequentiell oder parallel verarbeiteter Stream auf Basis eines Arrays
    • Stream.of(String-values oder Integer-values) –> Direkte Erstellung auf Basis von übergebenen Werten
    • IntStream.range(beginInt,endInt) –>Erzeugung eines IntStream mit Range von 7 bis 42, wobei das untere Ende des Intervals enthalten und die obere Grenze nicht enthalten ist
    • Stream<Path> kann durch die die Verwendung von Files.list() auf einem Verzeichnis etabliert werden
    • Files.lines() liest einen Stream<String> Textdatei
  2. Intermediate-Operationen:
    • filter() –> Aussortieren von Elementen auf dem Stream; Verwendung von .filter().filter() ist genauso möglich wie die Verwendung von .filter( (Bedingung).and(Bedingung))
    • distinct() –> Entfernung doppelter Einträge
    • sorted() –> Sortierung
    • skip(n) –> Überspringen der ersten n Elemente
    • limit(n) –> Begrenzung auf n Elemente
    • map() –> Mapping eines bestimmten Element(Typs) zu einem anderen Element(Typ); die Typumwandlung ist hierbei optional, wird aber sehr häufig genutzt
    • peek() –> Untersuchung des aktuellen Elements ohne ein Fortsetzen der Iteration
  3. Terminal-Operationen:
    • forEach() –> Behandlung jedes Elements des Stream
    • collect(Collectors.toList()) –> Alle Elemente des verarbeiteten Streams werden in eine Liste gespeichert
    • collect(Collectors.toMap(myElem::id,myElem::name)) –> Speicherung der aus dem Stream resultierenden Daten in eine Map<Integer,String)
    • collect(Collectors.groupingBy()) –> Gruppierung der Elemente
    • reduce() –> Reduzierung auf einen einzelnen Wert anhand des gegebenen Ausdrucks
    • anyMatch() –> Reduzierung auf einen boolschen Wert anhand des gegeben Predicates
    • findFirst() –> Reduzierung auf das erste Element gekapselt in einem Optional

Es gibt sehr viel mehr Beispiele als die, die hier aufgelistet sind. Gerade im Bereich der Collectors ist noch sehr viel Redebedarf ;-). Eine weitere wichtige Information ist, dass Streams lazy sind, das bedeutet, dass erst mit dem Hinzufügen einer Terminal-Operation die angegebenen Operationen auf einem Stream ausgeführt werden.

ZeroTurnaround hat einen brauchbaren Cheatsheet für den Einstieg veröffentlicht.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.