Java 8 (JSR 335): Lambdas, Streams, Funktionale Interfaces, Default-Methoden
Martin Lehmann und Markus Günther, Accso GmbH...
2
Copyright©2014
AccsoGmbH
About me
42 Jahre
Studium der Informatik an der Universität Würzburg
Berufsstart 1997
Einstieg ...
3
Copyright©2014
AccsoGmbH
Der steile und steinige Weg zu Java 8
(c) Helge Schütt, 2013, Hafencity HH
Java 8 GA seit
18. M...
4
Copyright©2014
AccsoGmbH
Agenda: Was kommt in Java 8 mit JSR 335?
Lambda-Ausdrücke
Verbesserte Typinferenz
Methodenrefer...
5
Copyright©2014
AccsoGmbH
Agenda: Was kommt in Java 8 mit JSR 335?
Lambda-Ausdrücke
Verbesserte Typinferenz
Methodenrefer...
6
Copyright©2014
AccsoGmbH
Was passiert, wenn ich einem Interface eine Methode
hinzufügen möchte?
public class FooImpl imp...
7
Copyright©2014
AccsoGmbH
Was passiert, wenn ich einem Interface eine Methode
hinzufügen möchte?
public interface Fooable...
8
Copyright©2014
AccsoGmbH
Unterscheide: Laufzeit- und Quelltextsicht bei
Kompatibilitätsbetrachtungen von modifizierten K...
9
Copyright©2014
AccsoGmbH
Zur Compile-Zeit muss eindeutig sein, welche Default-
Methode zur Link-Zeit in Implementierunge...
10
Copyright©2014
AccsoGmbH
Bei eindeutiger Methodenresolution wählt der Compiler die
spezifischste Implementierung einer ...
11
Copyright©2014
AccsoGmbH
Der Compiler zeigt einen Kompilierfehler an, falls er die
spezifischste Default-Methode nicht ...
12
Copyright©2014
AccsoGmbH
Konflikte muss der Entwickler explizit auflösen.
public interface D {
default void sayHello() ...
13
Copyright©2014
AccsoGmbH
Ist das nicht Mehrfachvererbung?
Ja, aber…
Mehrfachvererbung gibt es schon immer in Java:
Klas...
14
Copyright©2014
AccsoGmbH
Default-Methoden: Mehrfachvererbung kann zu
überraschenden Ergebnissen führen. lc01_interfaces...
15
Copyright©2014
AccsoGmbH
public interface C extends A {
default void result(int i, int j) {
System.out.println(
“C.resu...
16
Copyright©2014
AccsoGmbH
Ende
Image courtesy of phanlop88 / FreeDigitalPhotos.net
17
Copyright©2014
AccsoGmbH
Agenda: Was kommt in Java 8 mit JSR 335?
Lambda-Ausdrücke
Verbesserte Typinferenz
Methodenrefe...
18
Copyright©2014
AccsoGmbH
Lambda-Ausdrücke in Java 8
(Object o) -> o.toString()
Eigenschaften
Lambda-Ausdruck ist eine a...
19
Copyright©2014
AccsoGmbH
Lambda-Ausdrücke in Java 8
Ohne Typangabe x -> x + 1;
Mit Typangabe (Integer i) -> list.add(i)...
20
Copyright©2014
AccsoGmbH
Wozu benötigen wir Lambda-Ausdrücke in Java?
Code-as-Data
Verhalten in Form eines Lambda-Ausdr...
21
Copyright©2014
AccsoGmbH
Lambda-Ausdrücke ersetzen anonyme innere Klassen.
Bedeutung für
bisherigen Code
Äquivalenz zwi...
22
Copyright©2014
AccsoGmbH
Von Anonymous Inner Classes zu Lambdas lc02_anoninnerclass
Image courtesy of phanlop88 / FreeD...
23
Copyright©2014
AccsoGmbH
Anonyme innere Klassen lassen sich einfach in
äquivalente Lambda-Ausdrücke migrieren.
Comparat...
24
Copyright©2014
AccsoGmbH
Anonyme innere Klassen lassen sich einfach in
äquivalente Lambda-Ausdrücke migrieren.
Comparat...
25
Copyright©2014
AccsoGmbH
Anonyme innere Klassen lassen sich einfach in
äquivalente Lambda-Ausdrücke migrieren.
Comparat...
26
Copyright©2014
AccsoGmbH
Ende
Image courtesy of phanlop88 / FreeDigitalPhotos.net
27
Copyright©2014
AccsoGmbH
Performance?
Entnommen aus Joseph D. Darcy‘s Präsentation On the road to JDK 8 @ Devoxx 2012, ...
28
Copyright©2014
AccsoGmbH
Performance?
Entnommen aus Joseph D. Darcy‘s Präsentation On the road to JDK 8 @ Devoxx 2012, ...
29
Copyright©2014
AccsoGmbH
Agenda: Was kommt in Java 8 mit JSR 335?
Lambda-Ausdrücke
Verbesserte Typinferenz
Methodenrefe...
30
Copyright©2014
AccsoGmbH
Funktionale Interfaces repräsentieren das Typsystem für
einen Lambda-Ausdruck.
Funktionale
Int...
31
Copyright©2014
AccsoGmbH
Ein Lambda-Ausdruck evaluiert zu einem funktionalen
Interface.
Comparator<Integer> sortAscendi...
32
Copyright©2014
AccsoGmbH
Agenda: Was kommt in Java 8 mit JSR 335?
Lambda-Ausdrücke
Verbesserte Typinferenz
Methodenrefe...
33
Copyright©2014
AccsoGmbH
Im Package java.util.function sind funktionale
Interfaces, die für typische Use-Cases bestimmt...
34
Copyright©2014
AccsoGmbH
1) Das funktionale Interface Function<T,R> ist ein
Transformator eines Eingabetyps T in einen ...
35
Copyright©2014
AccsoGmbH
1) Ein typisches Nutzungsszenario für solche
Function<T,R> -Instanzen sind Transformatoren bei...
36
Copyright©2014
AccsoGmbH
2) Ein Consumer<T> ist eine Funktion, die den
Programmzustand durch Seiteneffekte verändert.
@...
37
Copyright©2014
AccsoGmbH
2) Ein typisches Nutzungsszenario für Consumer<T>
-Instanzen ist die Verarbeitung von Collecti...
38
Copyright©2014
AccsoGmbH
3) Ein Predicate<T> ist eine Funktion, die ein Objekt vom
Typ T einem logischen Test unterzieh...
39
Copyright©2014
AccsoGmbH
3) Ein typisches Nutzungsszenario für Predicate<T>
-Instanzen ist die Filterung von Collection...
40
Copyright©2014
AccsoGmbH
3) Predicate<T>-Instanzen kann man zu komplexeren
Testkriterien verknüpfen. lc03_predicates
Im...
41
Copyright©2014
AccsoGmbH
3) Predicate<T>-Instanzen kann man zu komplexeren
Testkriterien verknüpfen.
Einfaches Beispiel...
42
Copyright©2014
AccsoGmbH
Ende
Image courtesy of phanlop88 / FreeDigitalPhotos.net
43
Copyright©2014
AccsoGmbH
4) Ein Supplier<T> ist eine Factory-Funktion, die Objekte
vom Typ T liefert.
@FunctionalInterf...
44
Copyright©2014
AccsoGmbH
java.util.function enthält weitere funktionale
Interfaces - im Wesentlichen syntaktischer Zuck...
45
Copyright©2014
AccsoGmbH
Agenda: Was kommt in Java 8 mit JSR 335?
Lambda-Ausdrücke
Verbesserte Typinferenz
Methodenrefe...
46
Copyright©2014
AccsoGmbH
Das Design der Streams-API basiert auf einer
Pipes-and-Filters-Architektur.
ps –ef | grep logi...
47
Copyright©2014
AccsoGmbH
Interne Iteration, Streams, Filter/Map/Reduce lc04_streams
Image courtesy of phanlop88 / FreeD...
48
Copyright©2014
AccsoGmbH
Externe Iteratoren sind einfach zu benutzen, dafür aber
inhärent sequentiell und nicht zusamme...
49
Copyright©2014
AccsoGmbH
Die Steuerung einer internen Iteration obliegt dem
Container. Ein interner Iterator ist zusamm...
50
Copyright©2014
AccsoGmbH
Ende
Image courtesy of phanlop88 / FreeDigitalPhotos.net
51
Copyright©2014
AccsoGmbH
Das Design der Streams-API basiert auf einer Pipes-and-
Filters-Architektur.
prices.stream().f...
52
Copyright©2014
AccsoGmbH
Das Design der Streams-API basiert auf einer Pipes-and-
Filters-Architektur.
prices.stream().f...
53
Copyright©2014
AccsoGmbH
Das Design der Streams-API basiert auf einer Pipes-and-
Filters-Architektur.
prices.stream().f...
54
Copyright©2014
AccsoGmbH
Das Design der Streams-API basiert auf einer Pipes-and-
Filters-Architektur.
prices.stream().f...
55
Copyright©2014
AccsoGmbH
Intermediäre und terminale Operationen sind Wrapper
um einen Lambda-Ausdruck.
prices.stream()....
56
Copyright©2014
AccsoGmbH
Intermediäre und terminale Operationen sind Wrapper
um einen Lambda-Ausdruck.
prices.stream()....
57
Copyright©2014
AccsoGmbH
Intermediäre und terminale Operationen sind Wrapper
um einen Lambda-Ausdruck.
prices.stream()....
58
Copyright©2014
AccsoGmbH
Die Auswertung der Operationen erfolgt lazy bzw. eager.
prices.stream().filter(p -> p >= 40).m...
59
Copyright©2014
AccsoGmbH
Die Auswertung von intermed. Operationen erfolgt erst, wenn
der Stream durch eine terminale Op...
60
Copyright©2014
AccsoGmbH
String[] txt = { "State", "of", "the", "Lambda", "Libraries", "Edition" };
IntStream is =
Arra...
61
Copyright©2014
AccsoGmbH
Die Streams-API bietet eine Fülle generischer Methoden,
die wir zur Verarbeitung von Collectio...
62
Copyright©2014
AccsoGmbH
Die Streams-API bietet eine Fülle generischer Methoden,
die wir zur Verarbeitung von Collectio...
63
Copyright©2014
AccsoGmbH
Agenda: Was kommt in Java 8 mit JSR 335?
Lambda-Ausdrücke
Verbesserte Typinferenz
Methodenrefe...
64
Copyright©2014
AccsoGmbH
Fehlerbehandlung in Streams lc05_streams_errorhandling
Image courtesy of phanlop88 / FreeDigit...
65
Copyright©2014
AccsoGmbH
Error Handling in Streams (1/3)
ohne Exception-Handling in try/catch
String[] txt = { "abc", "...
66
Copyright©2014
AccsoGmbH
Error Handling in Streams (2/3)
Exception-Handling in der intermediären Operation
String[] txt...
67
Copyright©2014
AccsoGmbH
Error Handling in Streams (3/3)
Exception-Handling in der terminalen Operation
String[] txt = ...
68
Copyright©2014
AccsoGmbH
Ende
Image courtesy of phanlop88 / FreeDigitalPhotos.net
69
Copyright©2014
AccsoGmbH
Agenda: Was kommt in Java 8 mit JSR 335?
Lambda-Ausdrücke
Verbesserte Typinferenz
Methodenrefe...
70
Copyright©2014
AccsoGmbH
Wie kann man Programme überhaupt parallelisieren?
Schritt 1
Schritt 2
Schritt 3
Schritt 4
Schr...
71
Copyright©2014
AccsoGmbH
Wie kann man Programme überhaupt parallelisieren?
Schritt 1
Schritt 2
Schritt 3
Schritt 4
Schr...
72
Copyright©2014
AccsoGmbH
Wie kann man Programme überhaupt parallelisieren?
Schritt 1
Schritt 2
Schritt 3
Schritt 4
Schr...
73
Copyright©2014
AccsoGmbH
Fork-Join adressiert leicht zu parallelisierende Probleme
Teile und
Herrsche
Zerlege Problem s...
74
Copyright©2014
AccsoGmbH
Fork-Join-Baum der Aufgaben. Basis der Parallelisierung
ist Fork/Join-Framework aus Java7 (JSR...
75
Copyright©2014
AccsoGmbH
Sequentielle und parallele Streams:
Basis der Parallelisierung ist Fork/Join aus Java7 (JSR166...
76
Grenzen der Parallelisierung: Unterscheide zustandslose
von zustandsbehafteten intermediären Operationen
Zustandslose
i...
77
Was passiert in einem ParallelStream bei sorted()?
...stream().parallel() .statelessOps() .sorted() .statelessOps() .te...
78
Beispiel „Finde das maximale Elemente mit einem Parallel-
Stream“: Vorsicht beim Performance-Vergleich!
T
T1
T2
T1
T2
T...
79
Performance bei der Parallelisierung in Streams:
Old Style vs. Seq. Streams vs. Parallele Streams
Image courtesy of pha...
80
int[] ints = new int[64] ;
for (int i=0; i<64; i++) ints[i] = i;
List<String> stringList= new LinkedList<>();
Arrays.st...
81
Copyright©2014
AccsoGmbH
Literatur zum Thema von uns bei JavaSPEKTRUM und
Heise Developer… und die heutigen Folien auf ...
82
Copyright©2014
AccsoGmbH
Weitere Links und Literatur zu Java 8
https://jdk8.java.net/
http://www.techempower.com/blog/2...
Begeisterung für die
anspruchsvollen Aufgaben unserer Kunden
Individuelle
Kernsysteme
Beschleunigte
Softwaretechnik
Team≡
Nächste SlideShare
Wird geladen in …5
×

Java 8 (JSR335): Lambdas, Streams, Funktionale Interfaces, Default-Methoden

251 Aufrufe

Veröffentlicht am

Vortrag bei der Java User Group Frankfurt (JUGF) am 26.3.2014 (zusammen mit Markus Günther)

https://sites.google.com/site/jugffm/home/26-03-2014-java8-lambdas-streams-jsr33

Veröffentlicht in: Technologie
0 Kommentare
1 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
251
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
7
Aktionen
Geteilt
0
Downloads
2
Kommentare
0
Gefällt mir
1
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Java 8 (JSR335): Lambdas, Streams, Funktionale Interfaces, Default-Methoden

  1. 1. Java 8 (JSR 335): Lambdas, Streams, Funktionale Interfaces, Default-Methoden Martin Lehmann und Markus Günther, Accso GmbH Vortrag auf der Java User Group Frankfurt am 26. März 2014
  2. 2. 2 Copyright©2014 AccsoGmbH About me 42 Jahre Studium der Informatik an der Universität Würzburg Berufsstart 1997 Einstieg bei sd&m 2001 Verschiedene industrielle Softwareprojekte als Entwickler, Architekt, Projektmanager, Berater Mitarbeit bei sd&m Research zu Quasar von 2006-2007 Seit 2010 Mitglied der Geschäftsleitung und CTO beim IT-Dienstleister Accso – Accelerated Solutions GmbH in Darmstadt www.accso.de Interne Weiterbildung, Praktikum zu Java 8 im Sommer 2013 auf Basis JDK1.8b86 und IntelliJ 12 Veröffentlichungen zu Java 7 u. Java 8:
  3. 3. 3 Copyright©2014 AccsoGmbH Der steile und steinige Weg zu Java 8 (c) Helge Schütt, 2013, Hafencity HH Java 8 GA seit 18. März 2014! Java 6: Dezember 2006 Java 7: Juli 2011 Größte Neuerung und erste wesentliche Sprachänderung seit den Generics in Java 5: Lambda Expressions Umfrage von Typesafe im Feb‘14: Größte Vorfreude bei Entwicklern Lambdas mit 83% Collections/Streams mit 30%
  4. 4. 4 Copyright©2014 AccsoGmbH Agenda: Was kommt in Java 8 mit JSR 335? Lambda-Ausdrücke Verbesserte Typinferenz Methodenreferenzen Collections & Streams Filter/Map/Reduce, Parallelisierung Funktionale Interfaces Default- Methoden in Interfaces java.util.function
  5. 5. 5 Copyright©2014 AccsoGmbH Agenda: Was kommt in Java 8 mit JSR 335? Lambda-Ausdrücke Verbesserte Typinferenz Methodenreferenzen Collections & Streams Filter/Map/Reduce, Parallelisierung Funktionale Interfaces Default- Methoden in Interfaces java.util.function Nötig, um in Java 8 die Lambda-Ausdrücke für Java-Collections nutzbar zu machen bei gleichzeitiger Abwärtskompatibilität.
  6. 6. 6 Copyright©2014 AccsoGmbH Was passiert, wenn ich einem Interface eine Methode hinzufügen möchte? public class FooImpl implements Fooable { void foo() { System.out.println(“Hello!”); } } class App { // Version 1 public static void main(...) { new FooImpl().foo(); } } public interface Fooable { void foo(); // Version 1 }
  7. 7. 7 Copyright©2014 AccsoGmbH Was passiert, wenn ich einem Interface eine Methode hinzufügen möchte? public interface Fooable { void foo(); // Version 2 void bar(); } class App { // Version 2 public static void main(...) { new FooImpl().bar(); } } public class FooImpl implements Fooable { void foo() { System.out.println(“Hello!”); } } class App { // Version 1 public static void main(...) { new FooImpl().foo(); } } public interface Fooable { void foo(); // Version 1 } java.lang. NoSuchMethodError: Fooable.bar()V
  8. 8. 8 Copyright©2014 AccsoGmbH Unterscheide: Laufzeit- und Quelltextsicht bei Kompatibilitätsbetrachtungen von modifizierten Klassen. Laufzeitsicht Hinzufügen einer Interface-Methode ist binärkompatibel Wir können Fooable (Version 2) kompilieren … … und alle Class-Dateien, die das Interface nutzen, linken weiterhin VM „webt“ fehlende Methode zur Link-Zeit in die Klassen – diese Methode wirft NoSuchMethodError Quelltextsicht FooImpl muss Vertrag von Fooable (Version 2) erfüllen Hinzufügen einer Interface-Methode ist nicht abwärtskompatibel Default-Methods in Java 8 Default-Methode ist eine Methodenimplementierung im Interface VM „webt“ Default-Methode zur Link-Zeit in implementierende Klasse Schlüsselwort default zeigt Default-Methode im Interface an public interface Fooable { void foo(); default void bar() { /* Default-Implementierung im Interface */ } } Schlüsselwort default
  9. 9. 9 Copyright©2014 AccsoGmbH Zur Compile-Zeit muss eindeutig sein, welche Default- Methode zur Link-Zeit in Implementierungen genutzt wird. Regel 1 Class wins (Super-)Klasse hat immer Vorrang vor Interface („Class wins“) Gilt für konkrete und abstrakte Methoden in einer (Super-)Klasse Gibt es keine überschriebene Default-Methode in einer (Super)-Klasse, dann greift Regel 2 Regel 2 Subtype wins Spezifischstes Interface mit Default-Methode wählen („Subtype wins“) Beispiel: Default-Methode in List<E> hat Vorrang vor Default-Methode in Collection<E> Gibt es mehrere gleich-spezifische Interfaces, dann greift Regel 3 Regel 3 Konflikt kann nicht durch den Compiler aufgelöst werden Behandle Default-Methode, als wäre sie abstrakt Erfordert Implementierung in konkreter Klasse Nicht eindeutig?! Klasse kann mehrere Default-Methoden mit gleicher Signatur haben … weil Interface von anderem Interface erben kann … weil eine Klasse mehrere Interfaces implementieren kann Welche Default-Methode wählt der Compiler?
  10. 10. 10 Copyright©2014 AccsoGmbH Bei eindeutiger Methodenresolution wählt der Compiler die spezifischste Implementierung einer Default-Methode. public interface A { default void sayHello() { System.out.println(“Hallo aus A”); } } public interface B extends A { default void sayHello() { System.out.println(“Hallo aus B”); } } public class C1 implements A, B { public static void main(String[] args) { C1 c = new C1(); c.sayHello(); } } Ergebnis: „Hallo aus B“ B.sayHello ist spezifischste Implementierung aus Sicht von C1!
  11. 11. 11 Copyright©2014 AccsoGmbH Der Compiler zeigt einen Kompilierfehler an, falls er die spezifischste Default-Methode nicht zuordnen kann. public interface D { default void sayHello() { System.out.println(“D”); } } public interface E { default void sayHello() { System.out.println(“E”); } } public class C2 implements D, E { public static void main(String[] args) { C2 c = new C2(); c.sayHello(); } } C2 kompiliert nicht, da D und E „gleich-spezifisch“
  12. 12. 12 Copyright©2014 AccsoGmbH Konflikte muss der Entwickler explizit auflösen. public interface D { default void sayHello() { System.out.println(“D”); } } public interface E { default void sayHello() { System.out.println(“E”); } } public class C2 implements D, E { public static void main(String[] args) { C2 c = new C2(); c.sayHello(); } @Override public void sayHello() { D.super.sayHello(); } } C2 kompiliert nun wg. expliziter Auflösung
  13. 13. 13 Copyright©2014 AccsoGmbH Ist das nicht Mehrfachvererbung? Ja, aber… Mehrfachvererbung gibt es schon immer in Java: Klasse B kann von Klasse A ableiten und … zusätzliche Interfaces implementieren Aber das ist nicht Mehrfachvererbung von Zustand … sondern Mehrfachvererbung von Verhalten! Achtung: Default-Methoden sind virtuelle Methoden Spezifischste Default-Methode wird aus Sicht des dynamischen Typs ermittelt Kann zu überraschenden Resultaten führen
  14. 14. 14 Copyright©2014 AccsoGmbH Default-Methoden: Mehrfachvererbung kann zu überraschenden Ergebnissen führen. lc01_interfaces_defaultmethods Image courtesy of phanlop88 / FreeDigitalPhotos.net
  15. 15. 15 Copyright©2014 AccsoGmbH public interface C extends A { default void result(int i, int j) { System.out.println( “C.result = “ + calc(i, i)); } } public interface B extends A { default int calc(int i, int j) { return i * j; } } public interface C extends A { default void result(int i, int j) { System.out.println( “C.result = “ + calc(i, j)); } } public interface B extends A { default int calc(int i, int j) { return i * j; } } Die Mehrfachvererbung von Verhalten kann zu überraschenden Ergebnissen führen. public interface A { default void result(int i, int j) { System.out.println(“A.result = “ + calc(i, j)); } default int calc(int i, int j) { return i + j; } } public class Impl implements B, C { public static void main(String[] args) { new Impl().result(3, 4); // Ergebnis? } } Ergebnis: 12, nicht 7
  16. 16. 16 Copyright©2014 AccsoGmbH Ende Image courtesy of phanlop88 / FreeDigitalPhotos.net
  17. 17. 17 Copyright©2014 AccsoGmbH Agenda: Was kommt in Java 8 mit JSR 335? Lambda-Ausdrücke Verbesserte Typinferenz Methodenreferenzen Collections & Streams Filter/Map/Reduce, Parallelisierung Funktionale Interfaces Default- Methoden in Interfaces java.util.function
  18. 18. 18 Copyright©2014 AccsoGmbH Lambda-Ausdrücke in Java 8 (Object o) -> o.toString() Eigenschaften Lambda-Ausdruck ist eine anonyme Methode Hat Parameter, einen Rückgabetyp, einen Körper Operator für Lambda-Ausdrücke Parameterliste Körper Kann den umschließenden Scope nutzen (variable capture) (Person p) -> p.getName().equals(name) Kann existierende Methoden referenzieren Object::toString Operator für Methodenreferenzen
  19. 19. 19 Copyright©2014 AccsoGmbH Lambda-Ausdrücke in Java 8 Ohne Typangabe x -> x + 1; Mit Typangabe (Integer i) -> list.add(i); Block, explizites return (Integer a, Integer b) -> { if (a < b) return a + b; return a; } Ohne Parameter () -> System.out.println(“Hallo Lambda!”);
  20. 20. 20 Copyright©2014 AccsoGmbH Wozu benötigen wir Lambda-Ausdrücke in Java? Code-as-Data Verhalten in Form eines Lambda-Ausdrucks kodieren… … und als Parameter an eine generische Methode wie map oder filter übergeben Entkoppelt Kodierung von Ausführung (vgl. innere Klassen) Lesbarkeit Code ist Kommunikationsmittel Beschreibt das „was“, nicht das „wie“ Mächtigere, ausdrucksstärkere APIs möglich Funktionaler Programmierstil Höherer Abstraktionsgrad durch Funktionen höherer Ordnung Eleganter, kürzer, prägnanter Keine Seiteneffekte
  21. 21. 21 Copyright©2014 AccsoGmbH Lambda-Ausdrücke ersetzen anonyme innere Klassen. Bedeutung für bisherigen Code Äquivalenz zwischen Lambdas und anonyme innerer Klasse mit Single-Abstract-Method (SAM). Beispiele: Runnable, Comparator, ActionListener, … Lambda Führt keinen zusätzlichen Scope ein Damit kein Shadowing von Bezeichnern this bezieht sich auf die umschließende Klasse Ein return aber nicht! Anonyme innere Klasse Führt zusätzlichen Scope ein Daher Shadowing von Bezeichnern in verschiedenen Scopes this bezieht sich auf anonyme innere Klasse, umschließender Kontext über ClassName.this erreichbar
  22. 22. 22 Copyright©2014 AccsoGmbH Von Anonymous Inner Classes zu Lambdas lc02_anoninnerclass Image courtesy of phanlop88 / FreeDigitalPhotos.net
  23. 23. 23 Copyright©2014 AccsoGmbH Anonyme innere Klassen lassen sich einfach in äquivalente Lambda-Ausdrücke migrieren. Comparator<Integer> sortAscending = new Comparator<Integer>() { @Override public int compare(Integer a, Integer b) { return a-b; } }; Typischer Code für einen Comparator, der Ganzzahlen vergleicht … Comparator<Integer> sortAscending = new Comparator<Integer>() { @Override public int compare(Integer a, Integer b) { return a-b; } }; Warum muss ich compare überschreiben? Es ist die einzige Methode des Interface, mein Vorhaben ist doch klar?
  24. 24. 24 Copyright©2014 AccsoGmbH Anonyme innere Klassen lassen sich einfach in äquivalente Lambda-Ausdrücke migrieren. Comparator<Integer> sortAscending = new Comparator<Integer>() { @Override public int compare(Integer a, Integer b) { return a-b; } }; Comparator<Integer> sortAscending = (Integer a, Integer b) -> { return a-b; }; Reduktion auf das Wesentliche: Eingabedaten und Code-Block Die Definition eines Comparator-Interfaces erfordert viel Boilerplate-Code Comparator<Integer> sortAscending = new Comparator<Integer>() { @Override public int compare(Integer a, Integer b) { return a-b; } };
  25. 25. 25 Copyright©2014 AccsoGmbH Anonyme innere Klassen lassen sich einfach in äquivalente Lambda-Ausdrücke migrieren. Comparator<Integer> sortAscending = (Integer a, Integer b) -> { return a-b; }; Comparator<Integer> sortAscending = (Integer a, Integer b) -> a-b; Comparator<Integer> sortAscending = (a, b) -> a-b; … wir führen allerdings immer noch redundante Informationen mit … Block-Schreibweise und explizites return entfernen Der Compiler kann Typ- informationen inferieren
  26. 26. 26 Copyright©2014 AccsoGmbH Ende Image courtesy of phanlop88 / FreeDigitalPhotos.net
  27. 27. 27 Copyright©2014 AccsoGmbH Performance? Entnommen aus Joseph D. Darcy‘s Präsentation On the road to JDK 8 @ Devoxx 2012, Antwerpen Operationen / s Single-threaded Multi-threaded (saturiert) Faktor Anonyme innere Klasse 160 1407 8,8 Capturing Lambda 160 1400 8,8 Non Capturing Lambda 636 23201 36,4 Performance Lambda-Funktionen sind im Worst-Case so effizient wie anonyme innere Klassen, im Best-Case deutlich schneller. Oracle Performance Team hat Effizienzbetrachtungen durchgeführt (Daten von Herbst 2012). Lambdas ohne Zugriff auf umschließenden Kontext: Um Faktoren schneller!
  28. 28. 28 Copyright©2014 AccsoGmbH Performance? Entnommen aus Joseph D. Darcy‘s Präsentation On the road to JDK 8 @ Devoxx 2012, Antwerpen Kosten Anonyme innere Klasse Lambda-Ausdruck Link-Zeit Laden der Klasse Einmalige Kosten beim Aufsetzen der capture Konstruktion Konstruktor aufrufen Erzeugung des Lambda-Ausdrucks Aufruf invokeinterface invokedynamic
  29. 29. 29 Copyright©2014 AccsoGmbH Agenda: Was kommt in Java 8 mit JSR 335? Lambda-Ausdrücke Verbesserte Typinferenz Methodenreferenzen Collections & Streams Filter/Map/Reduce, Parallelisierung Funktionale Interfaces Default- Methoden in Interfaces java.util.function
  30. 30. 30 Copyright©2014 AccsoGmbH Funktionale Interfaces repräsentieren das Typsystem für einen Lambda-Ausdruck. Funktionale Interfaces Single-Abstract-Method-Typen (SAM-Typen) Darf nur eine abstrakte Methode enthalten … aber beliebig viele Default-Methoden Annotation java.lang.FunctionalInterface Beispiele: Runnable, Comparator, ActionListener, … Evaluation eines Lambda-Ausdrucks Funktionales Interface ist sog. Target Type für Lambda-Ausdruck Rückgabetyp der abstrakten Methode Parametertypen der abstrakten Methode Deklarierte Exceptions der abstrakten Methode Verbesserte Typinferenz von Java 8 bringt Lambda und Interface zusammen
  31. 31. 31 Copyright©2014 AccsoGmbH Ein Lambda-Ausdruck evaluiert zu einem funktionalen Interface. Comparator<Integer> sortAscending = (Integer a, Integer b) -> a-b; @FunctionalInterface public interface Comparator<T>() { int compare(T o1, T o2); ... }; Rückgabetyp stimmt überein Parametertyp stimmt überein
  32. 32. 32 Copyright©2014 AccsoGmbH Agenda: Was kommt in Java 8 mit JSR 335? Lambda-Ausdrücke Verbesserte Typinferenz Methodenreferenzen Collections & Streams Filter/Map/Reduce, Parallelisierung Funktionale Interfaces Default- Methoden in Interfaces java.util.function
  33. 33. 33 Copyright©2014 AccsoGmbH Im Package java.util.function sind funktionale Interfaces, die für typische Use-Cases bestimmt sind. Neue funktionale Interfaces 1. Function - Zur Abbildung von Funktionen 2. Consumer - Zur Abbildung von Prozeduren mit Seiteneffekten 3. Predicate - Zur Abbildung von Prädikaten 4. Supplier - Zur Abbildung von Objektfabriken Neue Klasse Optional<T> Vereinfacht Null-Behandlung im Code Methoden können einfach Optional<T> liefern Optional bietet viele Convenience-Methoden an Arbeiten mit funktionalen Interfaces zusammen @NotNull Optional<T> opt = ... opt.ifPresent(t -> doSomething(t));
  34. 34. 34 Copyright©2014 AccsoGmbH 1) Das funktionale Interface Function<T,R> ist ein Transformator eines Eingabetyps T in einen Ausgabetyp R. @FunctionalInterface public interface Function<T, R> { public R apply(T t); public default <V> Function<T, V> compose( Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } } Function<Integer, Integer> square = n -> n*n; assertEquals(9, square.apply(3)); Definition Einfaches Beispiel Definition Evaluation
  35. 35. 35 Copyright©2014 AccsoGmbH 1) Ein typisches Nutzungsszenario für solche Function<T,R> -Instanzen sind Transformatoren bei map() public static <I, O> List<O> map(Function<I, O> mapper, List<I> input) { final List<O> outputList = new ArrayList<>(); input.forEach(i -> { O o = mapper.apply(i); outputList.add(o); }); return outputList; } Code-as-Data Nicht Function<T,R>.apply(arg) direkt aufrufen, … … sondern Function<T,R> als Lambda-Ausdruck übergeben! map(x -> Integer.valueOf(x), input); generische Funktion Lambda-Ausdruck Daten
  36. 36. 36 Copyright©2014 AccsoGmbH 2) Ein Consumer<T> ist eine Funktion, die den Programmzustand durch Seiteneffekte verändert. @FunctionalInterface public interface Consumer<T> { public void accept(T t); public default Consumer<T> chain( Consumer<? super T> other) { Objects.requireNonNull(other); return (T t) -> { accept(t); other.accept(t);}; } } Definition Eigenschaften Analog zu Function<T,R>, aber keine Rückgabe sondern Seiteneffekt Mehrere Consumer<T> kann man miteinander verketten - Ausführung von links nach rechts Einfaches Beispiel Consumer<String> out = s -> System.out.println(s); out.accept("Test");
  37. 37. 37 Copyright©2014 AccsoGmbH 2) Ein typisches Nutzungsszenario für Consumer<T> -Instanzen ist die Verarbeitung von Collections mit forEach. public static <T> void forEach(Consumer<T> consumer, List<T> input) { for (T t : input) { consumer.accept(t); } } Code-as-Data Nicht Consumer<T>.accept(arg) direkt aufrufen, … … sondern Consumer<T> als Lambda-Ausdruck übergeben! forEach(s -> System.out.println(s), input); generische Funktion Lambda-Ausdruck Daten
  38. 38. 38 Copyright©2014 AccsoGmbH 3) Ein Predicate<T> ist eine Funktion, die ein Objekt vom Typ T einem logischen Test unterzieht. @FunctionalInterface public interface Predicate<T> { public boolean test(T t); public default Predicate<T> and(...) { ... } public default Predicate<T> negate() { ... } public default Predicate<T> or(...) { ... } public default Predicate<T> xor(...) { ... } } Definition
  39. 39. 39 Copyright©2014 AccsoGmbH 3) Ein typisches Nutzungsszenario für Predicate<T> -Instanzen ist die Filterung von Collections mit filter() public static <T> List<T> filter(Predicate<T> criterion, List<T> input) { final List<T> filteredList = new ArrayList<>(); input.forEach(i -> { if (criterion.test(i)) { filteredList.add(i); } }); return filteredList; } Code-as-Data Nicht Predicate<T>.test(arg) direkt aufrufen, … … sondern Predicate<T> als Lambda-Ausdruck übergeben! filter(n -> n % 2 == 0, input); generische Funktion Lambda-Ausdruck Daten
  40. 40. 40 Copyright©2014 AccsoGmbH 3) Predicate<T>-Instanzen kann man zu komplexeren Testkriterien verknüpfen. lc03_predicates Image courtesy of phanlop88 / FreeDigitalPhotos.net
  41. 41. 41 Copyright©2014 AccsoGmbH 3) Predicate<T>-Instanzen kann man zu komplexeren Testkriterien verknüpfen. Einfaches Beispiel Predicate<Integer> isEven = n -> n % 2 == 0; assertTrue(isEven.test(2)); Predicate<Integer> isOdd = isEven.negate(); assertTrue(isOdd.test(3)); Negation Und-Verknüpfung Predicate<Integer> isPositive = n -> n > 0; Predicate<Integer> isEvenAndPositive = isEven.and(isPositive); assertTrue(isEvenAndPositive.test(2)); assertFalse(isEvenAndPositive.test(0)); Oder-Verknüpfung Predicate<Integer> isZero = n -> n == 0; Predicate<Integer> isZeroOrPositive = isPositive.or(isZero); assertTrue(isZeroOrPositive.test(0));
  42. 42. 42 Copyright©2014 AccsoGmbH Ende Image courtesy of phanlop88 / FreeDigitalPhotos.net
  43. 43. 43 Copyright©2014 AccsoGmbH 4) Ein Supplier<T> ist eine Factory-Funktion, die Objekte vom Typ T liefert. @FunctionalInterface public interface Supplier<T> { public T get(); } Definition Einfaches Beispiel Supplier<Integer> generator = () -> (int) (Math.random() * NUMBER_RANGE); int randomNumber = generator.get(); assertTrue( randomNumber > 0 && randomNumber <= NUMBER_RANGE); Nutzung? Zufallszahlengeneratoren braucht man jetzt nicht so oft … Am ehesten als … Closure um Collection, aus der Elemente geholt werden Objektfabrik
  44. 44. 44 Copyright©2014 AccsoGmbH java.util.function enthält weitere funktionale Interfaces - im Wesentlichen syntaktischer Zucker… Binäre Funktionen BiConsumer BiFunction BiPredicate Typ- parametrierte Funktionen BinaryOperator … IntConsumer DoubleFunction LongFunction … LongBinary- Operator DoubleBinary- Operator … @FunctionalInterface public interface BinaryOperator<T> extends BiFunction<T,T,T> { }
  45. 45. 45 Copyright©2014 AccsoGmbH Agenda: Was kommt in Java 8 mit JSR 335? Lambda-Ausdrücke Verbesserte Typinferenz Methodenreferenzen Collections & Streams Filter/Map/Reduce, Parallelisierung Funktionale Interfaces Default- Methoden in Interfaces java.util.function
  46. 46. 46 Copyright©2014 AccsoGmbH Das Design der Streams-API basiert auf einer Pipes-and-Filters-Architektur. ps –ef | grep login | cut –c 50- | head Decrypt Authenticate De-Dup PipePipe Pipe Pipe Filter Filter Filter Incoming Order Clean Order Verkettung von Unix-Programmen Enterprise Integration Patterns
  47. 47. 47 Copyright©2014 AccsoGmbH Interne Iteration, Streams, Filter/Map/Reduce lc04_streams Image courtesy of phanlop88 / FreeDigitalPhotos.net
  48. 48. 48 Copyright©2014 AccsoGmbH Externe Iteratoren sind einfach zu benutzen, dafür aber inhärent sequentiell und nicht zusammensetzbar. List<Integer> prices = Arrays.asList(10, 20, 30, 40, 50); double totalCost = 0.0; for (Integer price : prices) { totalCost += price; } return totalCost; List<Integer> prices = Arrays.asList(10, 20, 30, 40, 50); double totalCost = 0.0; for (Integer price : prices) { totalCost += price * 0.9; } return totalCost; List<Integer> prices = Arrays.asList(10, 20, 30, 40, 50); double totalCost = 0.0; for (Integer price : prices) { if (price >= 40) totalCost += price * 0.9; } return totalCost; List<Integer> prices = Arrays.asList(10, 20, 30, 40, 50); double totalCost = 0.0; for (Integer price : prices) { if (price >= 40) totalCost += price * 0.9; } return totalCost; Eigenschaften Nicht parallelisierbar Nicht zusammensetzbar Iteration über Preise Filterung nach bestimmten Preisen Reduktion um 10% pro Preis Summierung der Teilergebnisse Reduktion und Summierung auch noch vermischt
  49. 49. 49 Copyright©2014 AccsoGmbH Die Steuerung einer internen Iteration obliegt dem Container. Ein interner Iterator ist zusammensetzbar. List<Integer> prices = Arrays.asList(10, 20, 30, 40, 50); return prices.stream() .sum(); List<Integer> prices = Arrays.asList(10, 20, 30, 40, 50); return prices.stream() .mapToDouble(price -> price * 0.9) .sum(); List<Integer> prices = Arrays.asList(10, 20, 30, 40, 50); return prices.stream() .filter(price -> price >= 40) .mapToDouble(price -> price * 0.9) .sum(); List<Integer> prices = Arrays.asList(10, 20, 30, 40, 50); return prices.stream() .filter(price -> price >= 40) .mapToDouble(price -> price * 0.9) .sum(); Eigenschaften Lambda-Funktion kodiert Verhalten … … wird an generische Methode des Containers übergeben Container entscheidet, ob sequentiell oder parallel und / oder lazy Dekomposition in einzelne, funktionale Aspekte Schritt 1, Schritt 2, …, Schritt k „Fluss“ ist sofort erkennbar
  50. 50. 50 Copyright©2014 AccsoGmbH Ende Image courtesy of phanlop88 / FreeDigitalPhotos.net
  51. 51. 51 Copyright©2014 AccsoGmbH Das Design der Streams-API basiert auf einer Pipes-and- Filters-Architektur. prices.stream().filter(p -> p >= 40).mapToDouble(p -> p * 0.9).sum(); Source
  52. 52. 52 Copyright©2014 AccsoGmbH Das Design der Streams-API basiert auf einer Pipes-and- Filters-Architektur. prices.stream().filter(p -> p >= 40).mapToDouble(p -> p * 0.9).sum(); Source IntermediateOp Stream<Integer>
  53. 53. 53 Copyright©2014 AccsoGmbH Das Design der Streams-API basiert auf einer Pipes-and- Filters-Architektur. prices.stream().filter(p -> p >= 40).mapToDouble(p -> p * 0.9).sum(); Source IntermediateOp Stream<Integer> IntermediateOp Stream<Integer>
  54. 54. 54 Copyright©2014 AccsoGmbH Das Design der Streams-API basiert auf einer Pipes-and- Filters-Architektur. prices.stream().filter(p -> p >= 40).mapToDouble(p -> p * 0.9).sum(); Source IntermediateOp Stream<Integer> IntermediateOp Stream<Integer> TerminalOp Stream<Double> Double
  55. 55. 55 Copyright©2014 AccsoGmbH Intermediäre und terminale Operationen sind Wrapper um einen Lambda-Ausdruck. prices.stream().filter(p -> p >= 40).mapToDouble(p -> p * 0.9).sum(); Source FilterOp Stream<Integer> IntermediateOp Stream<Integer> TerminalOp Stream<Double> Double Instanz von Predicate<Integer>
  56. 56. 56 Copyright©2014 AccsoGmbH Intermediäre und terminale Operationen sind Wrapper um einen Lambda-Ausdruck. prices.stream().filter(p -> p >= 40).mapToDouble(p -> p * 0.9).sum(); Source FilterOp Stream<Integer> MapOp Stream<Integer> TerminalOp Stream<Double> Double Instanz von Predicate<Integer> Instanz vonInstanz von ToDoubleFunction <Integer>
  57. 57. 57 Copyright©2014 AccsoGmbH Intermediäre und terminale Operationen sind Wrapper um einen Lambda-Ausdruck. prices.stream().filter(p -> p >= 40).mapToDouble(p -> p * 0.9).sum(); Source FilterOp Stream<Integer> MapOp Stream<Integer> ReduceOp Stream<Double> Double Instanz von Predicate<Integer> Instanz vonInstanz von ToDoubleFunction <Integer> Instanz von DoubleBinaryOperator
  58. 58. 58 Copyright©2014 AccsoGmbH Die Auswertung der Operationen erfolgt lazy bzw. eager. prices.stream().filter(p -> p >= 40).mapToDouble(p -> p * 0.9).sum(); Source FilterOp Stream<Integer> MapOp Stream<Integer> ReduceOp Stream<Double> Double Instanz von Predicate<Integer> Instanz vonInstanz von ToDoubleFunction <Integer> Instanz von DoubleBinaryOperator lazy lazy eager
  59. 59. 59 Copyright©2014 AccsoGmbH Die Auswertung von intermed. Operationen erfolgt erst, wenn der Stream durch eine terminale Operation angestossen wird. String[] txt = { "State", "of", "the", "Lambda", "Libraries", "Edition" }; IntStream is = Arrays.stream(txt). filter(s -> s.length() > 3). mapToInt(s -> { System.out.println(s + ","); return s.length(); }); // erste terminale Operation is.forEach(l -> System.out.print(l + ", ")); Mit der Variable is halten und nutzen wir eine Referenz auf den Stream. Das ist schlechter Stil und potentiell gefährlich, denn zwei oder mehr terminale Operationen könnten darauf aufgerufen werden, was nicht erlaubt ist. Nur eine terminale Operation ist möglich! Danach ist der Stream “verbraucht”.
  60. 60. 60 Copyright©2014 AccsoGmbH String[] txt = { "State", "of", "the", "Lambda", "Libraries", "Edition" }; IntStream is = Arrays.stream(txt). filter(s -> s.length() > 3). mapToInt(s -> { System.out.println(s + ","); return s.length(); }); // erste terminale Operation is.forEach(l -> System.out.print(l + ", ")); // zweite terminale Operation int sum = is.reduce(0, (l1, l2) -> { return (l1 + l2); }); Laufzeitfehler daher bei der zweiten terminalen Operation! Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:221) at java.util.stream.IntPipeline.reduce(IntPipeline.java:453) . . . Die Auswertung von intermed. Operationen erfolgt erst, wenn der Stream durch eine terminale Operation angestossen wird.
  61. 61. 61 Copyright©2014 AccsoGmbH Die Streams-API bietet eine Fülle generischer Methoden, die wir zur Verarbeitung von Collections nutzen können. Operation Rückgabe Evaluation Interface λ-Signatur filter Stream<T> lazy Predicate<T> T boolean map Stream<R> lazy Function<T, R> T R reduce T eager BinaryOperator<T> (T, T) T limit Stream<T> lazy - - findFirst Optional<T> eager - - forEach void eager Block<T> T void sorted Stream<T> lazy Comparator<T> (T, T) boolean collect Collection<R> eager - - anyMatch boolean eager Predicate<T> T boolean peek Stream<T> lazy - - ... ... ... ... ...
  62. 62. 62 Copyright©2014 AccsoGmbH Die Streams-API bietet eine Fülle generischer Methoden, die wir zur Verarbeitung von Collections nutzen können. Operation Rückgabe Evaluation Interface λ-Signatur filter Stream<T> lazy Predicate<T> T boolean map Stream<R> lazy Function<T, R> T R reduce T eager BinaryOperator<T> (T, T) T limit Stream<T> lazy - - findFirst Optional<T> eager - - forEach void eager Block<T> T void sorted Stream<T> lazy Comparator<T> (T, T) boolean collect Collection<R> eager - - anyMatch boolean eager Predicate<T> T boolean peek Stream<T> lazy - - ... ... ... ... ... peek() ist nützlich zum Debuggen. Wie geht das sonst?!?!? ... List<Integer> prices = Arrays.asList(10, 20, 30,40, 50, 60, 70); return prices.stream() .peek(price -> System.out.println(price)) .filter(price -> price >= 40) // Filter .peek(price -> System.out.println(price)) .mapToDouble(price -> price * 0.9) // Map: Rabatt .peek(price -> System.out.println(price)) .sum();
  63. 63. 63 Copyright©2014 AccsoGmbH Agenda: Was kommt in Java 8 mit JSR 335? Lambda-Ausdrücke Verbesserte Typinferenz Methodenreferenzen Collections & Streams Fehlerbehandlung Funktionale Interfaces Default- Methoden in Interfaces java.util.function
  64. 64. 64 Copyright©2014 AccsoGmbH Fehlerbehandlung in Streams lc05_streams_errorhandling Image courtesy of phanlop88 / FreeDigitalPhotos.net
  65. 65. 65 Copyright©2014 AccsoGmbH Error Handling in Streams (1/3) ohne Exception-Handling in try/catch String[] txt = { "abc", "abcde", "abc" }; // Stream wird aufgebaut Stream<Character> s1 = Arrays.stream(txt). map(t -> { // gezielte Exception fuer alle Strings mit Laenge > 3 if (t.length()>3) throw new RuntimeException("test too long"); return t.charAt(0); }); // Stream wird konsumiert s1.forEach( c -> System.out.print(c.charValue() + ",") ); Ausgabe: a, danach Exception (da abcde zu lange ist). abc wird nicht mehr verarbeitet.
  66. 66. 66 Copyright©2014 AccsoGmbH Error Handling in Streams (2/3) Exception-Handling in der intermediären Operation String[] txt = { "rst", "rstuv", "rst" }; // Stream wird aufgebaut Stream<Character> s2 = Arrays.stream(txt). map(t -> { try { if (t.length()>3) throw new RuntimeException("test too long"); return t.charAt(0); } catch (Exception ex) { return null; } }); // Stream wird konsumiert s2.forEach(c -> { if (c!=null) System.out.print(c.charValue() + ","); }); Ausgabe: r und r
  67. 67. 67 Copyright©2014 AccsoGmbH Error Handling in Streams (3/3) Exception-Handling in der terminalen Operation String[] txt = { "xyz", "vwxyz", "xyz" }; // Stream wird aufgebaut Stream<Character> s3 = Arrays.stream(txt). map(t -> { if (t.length()>3) throw new RuntimeException("test too long"); return t.charAt(0); }); // Stream wird konsumiert s3.forEach( c -> { try { System.out.print(c.charValue() + ","); } catch (Exception ex) { ex.printStackTrace(System.err); } } ); Ausgabe: x, danach Exception (da vwxyz zu lange ist). xyz wird nicht mehr verarbeitet.
  68. 68. 68 Copyright©2014 AccsoGmbH Ende Image courtesy of phanlop88 / FreeDigitalPhotos.net
  69. 69. 69 Copyright©2014 AccsoGmbH Agenda: Was kommt in Java 8 mit JSR 335? Lambda-Ausdrücke Verbesserte Typinferenz Methodenreferenzen Collections & Streams Parallelisierung Funktionale Interfaces Default- Methoden in Interfaces java.util.function
  70. 70. 70 Copyright©2014 AccsoGmbH Wie kann man Programme überhaupt parallelisieren? Schritt 1 Schritt 2 Schritt 3 Schritt 4 Schritt 5 Schritt 6 Variante 1: Parallelisierung des Datenflussesfor1...kdo Schritt 1 Schritt 2 Schritt 3 Schritt 4 Schritt 5 Schritt 6 foreachelementdoinparallel Schritt 1 Schritt 2 Schritt 3 Schritt 4 Schritt 5 Schritt 6 Schritt 1 Schritt 2 Schritt 3 Schritt 4 Schritt 5 Schritt 6 Schritt 1 Schritt 2 Schritt 3 Schritt 4 Schritt 5 Schritt 6 ......
  71. 71. 71 Copyright©2014 AccsoGmbH Wie kann man Programme überhaupt parallelisieren? Schritt 1 Schritt 2 Schritt 3 Schritt 4 Schritt 5 Schritt 6 Schritt 1 Schritt 2 Schritt 3 4a 4b 4c Schritt 5 Schritt 6 Variante 2: Parallelisierung des Kontrollflusses
  72. 72. 72 Copyright©2014 AccsoGmbH Wie kann man Programme überhaupt parallelisieren? Schritt 1 Schritt 2 Schritt 3 Schritt 4 Schritt 5 Schritt 6 Schritt 1 Schritte 2-5 Schritt 6 2-5.1 2-5.2 2-5.n 2-5.1.1 2-5.1.2 2-5.1.n Variante 2b: rekursive Parallelisierung des Kontrollflusses Fork/Join mit Teile&Herrsche!
  73. 73. 73 Copyright©2014 AccsoGmbH Fork-Join adressiert leicht zu parallelisierende Probleme Teile und Herrsche Zerlege Problem sukzessive in Teilprobleme ... bis Teilproblem klein genug, so dass es direkt gelöst werden kann ... und führe dann die Ergebnisse zusammen „embarassingly parallel“ // join loeseProblemMitForkJoin (Problem p) if (p ist klein genug) loese p direkt und sequentiell else teile p in unabhängige Teilprobleme p1 und p2 // split loese p1 und p2 unabhängig voneinander (rekursiv) // fork führe Teilergebnisse von p1 und p2 zusammen // join
  74. 74. 74 Copyright©2014 AccsoGmbH Fork-Join-Baum der Aufgaben. Basis der Parallelisierung ist Fork/Join-Framework aus Java7 (JSR166y). T rekursive Aufteilung in Teilprobleme in der Fork-Phase Zusammenführung der Teilergebnisse in der Join-Phase Problem klein genug? Sequentielle Berechnung T1 T2 T1 T2 T1 T2 T1 T2 TT t T11 T21 T22 T12 T11 T21 T22 T12
  75. 75. 75 Copyright©2014 AccsoGmbH Sequentielle und parallele Streams: Basis der Parallelisierung ist Fork/Join aus Java7 (JSR166y) String[] txt = { "State", "of", "the", "Lambda", "Libraries", "Edition" }; IntStream is = Arrays.stream(txt). filter(s -> s.length() > 3). mapToInt(s -> s.length()); int sum = is.reduce(0, (l1, l2) -> { return (l1 + l2); }); String[] txt = { "State", "of", "the", "Lambda", "Libraries", "Edition" }; IntStream is = Arrays.stream(txt).parallel(). // auch: Collection.parallelStream() filter(s -> s.length() > 3). mapToInt(s -> s.length()); int sum = is.reduce(0, (l1, l2) -> { return (l1 + l2); });
  76. 76. 76 Grenzen der Parallelisierung: Unterscheide zustandslose von zustandsbehafteten intermediären Operationen Zustandslose intermediäre Operationen Zustandslose intermediäre Operationen bearbeiten ein einzelnes Element Beispiele filter map Problemlos parallelisierbar, keine Synchronisierung erforderlich Zustandsbehaftete intermediäre Operationen benötigen einen zusätzlichen Kontext Beispiele limit nur die ersten k Elemente distinct nur disjunkte Elemente sorted Sortierung, siehe Folgefolie Schwierig parallelisierbar Zustandsbehaftete intermediäre Operationen
  77. 77. 77 Was passiert in einem ParallelStream bei sorted()? ...stream().parallel() .statelessOps() .sorted() .statelessOps() .terminal() Barriere: Parallelisierung wird hier gezielt sequentialisiert. Ergebnisse werden zwischengepuffert (auch bei seq. Stream!) Parallelisierung wird neu aufgesetzt Sequentielle Bearbeitung (in einem Thread).
  78. 78. 78 Beispiel „Finde das maximale Elemente mit einem Parallel- Stream“: Vorsicht beim Performance-Vergleich! T T1 T2 T1 T2 T1 T2 T1 T2 TT T11 T21 T22 T12 [1, n] [1, ] [ + 1, n] max(T11,T12) max(T21,T22) max(T1,T2) [1, ] [ + 1, ] [ + 1, ] [ + 1, n] int[] ints = { 17, 453, 5, 1, 458, 48, 6, 99, /* ... etc. ... */ }; int max = Arrays.stream(ints).parallel(). reduce(Integer.MIN_VALUE, (i,j) -> Math.max(i,j)); System.out.println(max);
  79. 79. 79 Performance bei der Parallelisierung in Streams: Old Style vs. Seq. Streams vs. Parallele Streams Image courtesy of phanlop88 / FreeDigitalPhotos.net lc06_streams_parallel
  80. 80. 80 int[] ints = new int[64] ; for (int i=0; i<64; i++) ints[i] = i; List<String> stringList= new LinkedList<>(); Arrays.stream(ints).parallel() .mapToObj(String::valueOf) .forEach(stringList::add); System.out.println(stringList); int[] ints = new int[64] ; for (int i=0; i<64; i++) ints[i] = i; List<String> stringList= new LinkedList<>(); Arrays.stream(ints).parallel() .mapToObj(String::valueOf) .sequential() .forEach(stringList::add); System.out.println(stringList); Sequentieller/Paralleler Moduswechsel und -Check im Stream selbst möglich! Methoden Stream.isParallel() Check, ob Stream parallel ist Stream.parallel() Modifikation des Streams ... Stream.sequential() ... zu par./seq. Stream möglich int[] ints = new int[64] ; for (int i=0; i<64; i++) ints[i] = i; List<String> stringList = new LinkedList<>(); Arrays.stream(ints) .mapToObj(String::valueOf) .forEach(stringList::add); System.out.println(stringList); Achtung: Nicht thread-safe!
  81. 81. 81 Copyright©2014 AccsoGmbH Literatur zum Thema von uns bei JavaSPEKTRUM und Heise Developer… und die heutigen Folien auf accso.de Markus Günther, Martin Lehmann „Lambda-Ausdrücke in Java 8“. In JavaSPEKTRUM, 03/2013 PDF-Download hier: http://www.sigs- datacom.de/fachzeitschriften/javaspektrum/archiv/artikelansicht.html?tx_mwjournals_pi 1[pointer]=0&tx_mwjournals_pi1[mode]=1&tx_mwjournals_pi1[showUid]=7237 Markus Günther, Martin Lehmann „Java 7: Das Fork-Join-Framework für mehr Performance“ In JavaSPEKTRUM, 05/2012 PDF-Download hier: http://www.sigs- datacom.de/fachzeitschriften/javaspektrum/archiv/artikelansicht.html?tx_mwjournals_pi 1[pointer]=0&tx_mwjournals_pi1[mode]=1&tx_mwjournals_pi1[showUid]=7396 Markus Günther, Martin Lehmann „Streams und Collections in Java 8“. Heise Developer, http://www.heise.de/developer/artikel/Streams-und- Collections-in-Java-8-2151376.html
  82. 82. 82 Copyright©2014 AccsoGmbH Weitere Links und Literatur zu Java 8 https://jdk8.java.net/ http://www.techempower.com/blog/2013/03/26/everything- about-java-8/ http://www.heise.de/developer/artikel/Was-Entwickler-mit-Java-8- erwartet-1932997.html Weitere Links
  83. 83. Begeisterung für die anspruchsvollen Aufgaben unserer Kunden Individuelle Kernsysteme Beschleunigte Softwaretechnik Team≡

×