class: center, middle, first # Software-Entwicklung 2 ### Streams --- # Fragen? > Fragen zur letzten Vorlesung? --- # Themen * Einführung * Stream Operationen * Ausführungsreihenfolge * Optimierungen * `reduce` * Parallel Streams --- # Einführung * Eingeführt mit Java 8 * Hat nichts mit Streams aus dem Java I/O-Package zu tun * Erlaubt [Funktionale Programmierung][wiki01] in Java --- # Erstes Beispiel ```java List
myList = Arrays.asList("a1", "a2", "b1", "c2", "c1"); myList .stream() .filter(s -> s.startsWith("c")) .map(String::toUpperCase) .sorted() .forEach(System.out::println); ``` _Quelle: [Java 8 Stream Tutorial][winterberg01]_ > Ausgabe? --- # Stream Operationen * Intermediate operations * Geben einen Stream zurück * Verkettung möglich * Terminal operations * Starten und Beenden den Stream * Geben entweder `void` oder ein Ergebnis zurück * Keine weitere Verkettung möglich Liste aller Stream-Operationen: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html --- # Stream Operationen Die meisten Stream-Operationen müssen **seiteneffektfrei** und **zustandslos** sein. ### Seiteneffektfrei > Daten des Streams werden nicht verändert ### Zustandslos > Die Operaion ist deterministisch: Ergebnis der Berechnung hängt nicht von externen Variablen ab --- # Stream Operationen ### Nicht blockierende Funktionen > Die von Ihnen in den Stream gestellten Funktionen blockieren nirgends (z.B. warten auf Disk I/O) --- # Stream Operationen * Vier Typen von Intermediate operations: * **Predicate**: Funktion, die einen Parameter besitzt und `true` oder `false` zurückgibt -> z.B. `filter()` * **Function**: Funktion, die einen Parameter besitzt und einen Wert zurückliefert -> z.B. `map()` * **Consumer**: Funktion, die Parameter besitzt aber nichts zurückgibt -> z.B. `println()` * **Producer**: Funktion ohne Parameter, die Werte zurückgibt -> z.B. `stream()` --- # "Lazy" Streams: Pipeline Pattern * Streams operieren "lazy" * Daten wandern durch die Verarbeitungspipeline * Es sind Daten in allen Verarbeitungsstufen vorhanden (Sonderfall `sort()`) --- # "Lazy" Streams: Sei Faul!! * Sobald die Terminalfunction erfüllt ist, bricht die Verarbeitung ab (z.B. `findFirst()`)
--- # Not "Lazy" 1 * Sobald die Terminalfunction erfüllt ist, bricht die Verarbeitung ab (z.B. `findFirst()`)
--- # Not "Lazy" 2 * Sobald die Terminalfunction erfüllt ist, bricht die Verarbeitung ab (z.B. `findFirst()`)
--- # Not "Lazy" 3 * Sobald die Terminalfunction erfüllt ist, bricht die Verarbeitung ab (z.B. `findFirst()`)
--- # Ausführungsreihenfolge > Was passiert? Ausgabe? ```java Stream.of("d2", "a2", "b1", "b3", "c") .filter(s -> { System.out.println("filter: " + s); return true; }); ``` _Quelle: [Java 8 Stream Tutorial][winterberg01]_ --- # Ausführungsreihenfolge > Was passiert? Ausgabe? ```java Stream.of("d2", "a2", "b1", "b3", "c") .filter(s -> { System.out.println("filter: " + s); return true; }) .forEach(s -> System.out.println("forEach: " + s)); ``` _Quelle: [Java 8 Stream Tutorial][winterberg01]_ --- # Ausführungsreihenfolge > Was passiert? Ausgabe? ```java Stream.of("d2", "a2", "b1", "b3", "c") .map(s -> { System.out.println("map: " + s); return s.toUpperCase(); }) .anyMatch(s -> { System.out.println("anyMatch: " + s); return s.startsWith("A"); }); ``` _Quelle: [Java 8 Stream Tutorial][winterberg01]_ --- # Optimierungen > Was könnte optimiert werden? ```java Stream.of("d2", "a2", "b1", "b3", "c") .map(s -> { System.out.println("map: " + s); return s.toUpperCase(); }) .filter(s -> { System.out.println("filter: " + s); return s.startsWith("A"); }) .forEach(s -> System.out.println("forEach: " + s)); ``` _Quelle: [Java 8 Stream Tutorial][winterberg01]_ --- # Sonderfall `sort()` Wird immer auf die _gesamte_ Collection angewandt. > Optimierungen? ```java Stream.of("d2", "a2", "b1", "b3", "c") .sorted((s1, s2) -> { System.out.printf("sort: %s; %s\n", s1, s2); return s1.compareTo(s2); }) .filter(s -> { System.out.println("filter: " + s); return s.startsWith("a"); }) .map(s -> { System.out.println("map: " + s); return s.toUpperCase(); }) .forEach(s -> System.out.println("forEach: " + s)); ``` _Quelle: [Java 8 Stream Tutorial][winterberg01]_ --- # `collect()` und `Collectors` > s. [Java 8 Stream Tutorial][winterberg01]: Collect --- # `reduce()` * Reduziert den Stream auf einen Wert. * Z.B. Durchschnittsalter aller Personen, die in einer Collection gespeichert sind. * Single threaded `reduce()`: `reduce(identidy value, accumulator)` * Identity value: Startwert * Accumulator: Funktion, die die übergegbenen Werte aggregiert Beispiel ```java Person result = persons .stream() .reduce(new Person("", 0), (p1, p2) -> { p1.age += p2.age; p1.name += p2.name; return p1; }); System.out.format("name=%s; age=%s", result.name, result.age); ``` _Quelle: [Java 8 Stream Tutorial][winterberg01]_ --- # `reduce()` * Single threaded `reduce()`: `reduce(identidy value, accumulator, combiner)` * Identity value: Startwert * Accumulator: Funktion, die die übergegbenen Werte aggregiert * Combiner: Funktion, die die einzelnen aggregierten Werte zusammenrechnet Beispiel ```java Integer ageSum = persons .parallelStream() // wichtig!! .reduce(0, (sum, p) -> { System.out.format("accumulator: sum=%s; person=%s\n", sum, p); return sum += p.age; }, (sum1, sum2) -> { System.out.format("combiner: sum1=%s; sum2=%s\n", sum1, sum2); return sum1 + sum2; }); ``` _Quelle: [Java 8 Stream Tutorial][winterberg01]_ --- # Parallel Streams * Parallele Ausführung des Streams * Sinnvoll bei (sehr) großen Datenmengen * Verwendung: `parallelStream() ` oder `stream.parallel()` statt `stream()` * `sort()`: So spät wie möglich aufrufen! * Verwenden von `reduce()`: `reduce(identidy value, accumulator, combiner)` notwendig --- # Seiteneffekt 1 * Single-threaded stream mit Seiteneffekt: Hässlich aber noch kein Fehler!
--- # Seiteneffekt 2: Jemand schaltet um auf "parallel"... * Parallel stream mit Seiteneffekt: Hässlich UND falsche Werte im counter!!!
> https://dzone.com/articles/think-twice-using-java-8 --- --- class: center, middle # Fragen? [wiki01]: https://de.wikipedia.org/wiki/Funktionale_Programmierung [winterberg01]: http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/