Top Banner
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
83

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

Apr 14, 2017

Download

Technology

Martin Lehmann
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Java 8 (JSR335): Lambdas, Streams, Funktionale Interfaces, Default-Methoden

Java 8 (JSR 335): Lambdas, Streams, Funktionale Interfaces, Default-MethodenMartin Lehmann und Markus Günther, Accso GmbH

Vortrag auf der Java User Group Frankfurt am 26. März 2014

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

2

Co

pyr

igh

201

4 A

ccso

Gm

bHAbout 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-DienstleisterAccso – Accelerated Solutions GmbH in Darmstadtwww.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:

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

3

Co

pyr

igh

201

4 A

ccso

Gm

bHDer 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%

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

4

Co

pyr

igh

201

4 A

ccso

Gm

bHAgenda: Was kommt in Java 8 mit JSR 335?

Lambda-Ausdrücke

Verbesserte Typinferenz

Methodenreferenzen

Collections & Streams

Filter/Map/Reduce, Parallelisierung

Funktionale InterfacesDefault-

Methoden

in

Interfacesjava.util.function

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

5

Co

pyr

igh

201

4 A

ccso

Gm

bHAgenda: 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.

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

6

Co

pyr

igh

201

4 A

ccso

Gm

bH

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 1public static void main(...) {new FooImpl().foo();

}}

public interface Fooable {void foo(); // Version 1

}

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

7

Co

pyr

igh

201

4 A

ccso

Gm

bH

Was passiert, wenn ich einem Interface eine Methode hinzufügen möchte?

public interface Fooable {void foo(); // Version 2void bar();

}

class App { // Version 2public static void main(...) {new FooImpl().bar();

}}

public class FooImpl implements Fooable {void foo() {System.out.println(“Hello!”);

}}

class App { // Version 1public static void main(...) {new FooImpl().foo();

}}

public interface Fooable {void foo(); // Version 1

}

java.lang.NoSuchMethodError: Fooable.bar()V

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

8

Co

pyr

igh

201

4 A

ccso

Gm

bH

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-Methodsin 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

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

9

Co

pyr

igh

201

4 A

ccso

Gm

bH

Zur Compile-Zeit muss eindeutig sein, welche Default-Methode zur Link-Zeit in Implementierungen genutzt wird.

Regel 1Class 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 2Subtype 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?

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

10

Co

pyr

igh

201

4 A

ccso

Gm

bH

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!

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

11

Co

pyr

igh

201

4 A

ccso

Gm

bH

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“

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

12

Co

pyr

igh

201

4 A

ccso

Gm

bHKonflikte 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();

}

@Overridepublic void sayHello() {D.super.sayHello();

}}

C2 kompiliert nun

wg. expliziter

Auflösung

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

13

Co

pyr

igh

201

4 A

ccso

Gm

bHIst 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

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

14

Co

pyr

igh

201

4 A

ccso

Gm

bH

Default-Methoden: Mehrfachvererbung kann zu überraschenden Ergebnissen führen. lc01_interfaces_defaultmethods

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

15

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

16

Co

pyr

igh

201

4 A

ccso

Gm

bH

Ende

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

17

Co

pyr

igh

201

4 A

ccso

Gm

bHAgenda: Was kommt in Java 8 mit JSR 335?

Lambda-Ausdrücke

Verbesserte Typinferenz

Methodenreferenzen

Collections & Streams

Filter/Map/Reduce, Parallelisierung

Funktionale InterfacesDefault-

Methoden

in

Interfacesjava.util.function

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

18

Co

pyr

igh

201

4 A

ccso

Gm

bHLambda-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

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

19

Co

pyr

igh

201

4 A

ccso

Gm

bHLambda-Ausdrücke in Java 8

Ohne Typangabex -> 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!”);

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

20

Co

pyr

igh

201

4 A

ccso

Gm

bHWozu 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

FunktionalerProgrammierstil

� Höherer Abstraktionsgrad durch Funktionen höherer Ordnung

� Eleganter, kürzer, prägnanter

� Keine Seiteneffekte

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

21

Co

pyr

igh

201

4 A

ccso

Gm

bHLambda-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

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

22

Co

pyr

igh

201

4 A

ccso

Gm

bHVon Anonymous Inner Classes zu Lambdas

lc02_anoninnerclass

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

23

Co

pyr

igh

201

4 A

ccso

Gm

bH

Anonyme innere Klassen lassen sich einfach in äquivalente Lambda-Ausdrücke migrieren.

Comparator<Integer> sortAscending = new Comparator<Integer>() {@Overridepublic int compare(Integer a, Integer b) {return a-b;

}};

Typischer Code für einen Comparator, der Ganzzahlen vergleicht …

Comparator<Integer> sortAscending = new Comparator<Integer>() {@Overridepublic 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?

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

24

Co

pyr

igh

201

4 A

ccso

Gm

bH

Anonyme innere Klassen lassen sich einfach in äquivalente Lambda-Ausdrücke migrieren.

Comparator<Integer> sortAscending = new Comparator<Integer>() {@Overridepublic 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>() {@Overridepublic int compare(Integer a, Integer b) {return a-b;

}};

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

25

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

26

Co

pyr

igh

201

4 A

ccso

Gm

bHEnde

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

27

Co

pyr

igh

201

4 A

ccso

Gm

bHPerformance?

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!

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

28

Co

pyr

igh

201

4 A

ccso

Gm

bHPerformance?

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 Aufsetzender capture

Konstruktion Konstruktor aufrufen Erzeugung des Lambda-Ausdrucks

Aufruf invokeinterface invokedynamic

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

29

Co

pyr

igh

201

4 A

ccso

Gm

bHAgenda: Was kommt in Java 8 mit JSR 335?

Lambda-Ausdrücke

Verbesserte Typinferenz

Methodenreferenzen

Collections & Streams

Filter/Map/Reduce, Parallelisierung

Funktionale InterfacesDefault-

Methoden

in

Interfacesjava.util.function

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

30

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

31

Co

pyr

igh

201

4 A

ccso

Gm

bH

Ein Lambda-Ausdruck evaluiert zu einem funktionalen Interface.

Comparator<Integer> sortAscending = (Integer a, Integer b) -> a-b;

@FunctionalInterfacepublic interface Comparator<T>() {

int compare(T o1, T o2);...

};

Rückgabetyp stimmt überein

Parametertyp stimmt überein

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

32

Co

pyr

igh

201

4 A

ccso

Gm

bHAgenda: Was kommt in Java 8 mit JSR 335?

Lambda-Ausdrücke

Verbesserte Typinferenz

Methodenreferenzen

Collections & Streams

Filter/Map/Reduce, Parallelisierung

Funktionale InterfacesDefault-

Methoden

in

Interfacesjava.util.function

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

33

Co

pyr

igh

201

4 A

ccso

Gm

bH

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));

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

34

Co

pyr

igh

201

4 A

ccso

Gm

bH

1) Das funktionale Interface Function<T,R> ist ein Transformator eines Eingabetyps T in einen Ausgabetyp R.

@FunctionalInterfacepublic 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

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

35

Co

pyr

igh

201

4 A

ccso

Gm

bH

1) Ein typisches Nutzungsszenario für solcheFunction<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

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

36

Co

pyr

igh

201

4 A

ccso

Gm

bH

2) Ein Consumer<T> ist eine Funktion, die den Programmzustand durch Seiteneffekte verändert.

@FunctionalInterfacepublic 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 BeispielConsumer<String> out = s -> System.out.println(s);out.accept("Test");

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

37

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

38

Co

pyr

igh

201

4 A

ccso

Gm

bH

3) Ein Predicate<T> ist eine Funktion, die ein Objekt vom Typ T einem logischen Test unterzieht.

@FunctionalInterfacepublic 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

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

39

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

40

Co

pyr

igh

201

4 A

ccso

Gm

bH

3) Predicate<T>-Instanzen kann man zu komplexeren Testkriterien verknüpfen. lc03_predicates

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

41

Co

pyr

igh

201

4 A

ccso

Gm

bH

3) Predicate<T>-Instanzen kann man zu komplexeren Testkriterien verknüpfen.

Einfaches BeispielPredicate<Integer> isEven = n -> n % 2 == 0;assertTrue(isEven.test(2));

Predicate<Integer> isOdd = isEven.negate();assertTrue(isOdd.test(3));

Negation

Und-VerknüpfungPredicate<Integer> isPositive = n -> n > 0;Predicate<Integer> isEvenAndPositive =

isEven.and(isPositive);assertTrue(isEvenAndPositive.test(2));assertFalse(isEvenAndPositive.test(0));

Oder-VerknüpfungPredicate<Integer> isZero = n -> n == 0;Predicate<Integer> isZeroOrPositive =

isPositive.or(isZero);assertTrue(isZeroOrPositive.test(0));

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

42

Co

pyr

igh

201

4 A

ccso

Gm

bHEnde

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

43

Co

pyr

igh

201

4 A

ccso

Gm

bH

4) Ein Supplier<T> ist eine Factory-Funktion, die Objekte vom Typ T liefert.

@FunctionalInterfacepublic interface Supplier<T> {public T get();

}

Definition

Einfaches BeispielSupplier<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

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

44

Co

pyr

igh

201

4 A

ccso

Gm

bH

java.util.function enthält weitere funktionale Interfaces - im Wesentlichen syntaktischer Zucker…

Binäre

FunktionenBiConsumer

BiFunction

BiPredicate

Typ-

parametrierte

Funktionen

BinaryOperator

IntConsumer

DoubleFunction

LongFunction

LongBinary-

Operator

DoubleBinary-

Operator

@FunctionalInterfacepublic interface BinaryOperator<T> extends BiFunction<T,T,T> {}

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

45

Co

pyr

igh

201

4 A

ccso

Gm

bHAgenda: Was kommt in Java 8 mit JSR 335?

Lambda-Ausdrücke

Verbesserte Typinferenz

Methodenreferenzen

Collections & Streams

Filter/Map/Reduce, Parallelisierung

Funktionale InterfacesDefault-

Methoden

in

Interfacesjava.util.function

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

46

Co

pyr

igh

201

4 A

ccso

Gm

bH

Das Design der Streams-API basiert auf einer Pipes-and-Filters-Architektur.

ps –ef | grep login | cut –c 50- | head

Decrypt Authenticate De-DupPipePipe Pipe Pipe

Filter Filter FilterIncoming

Order

Clean

Order

Verkettung von Unix-Programmen

Enterprise Integration Patterns

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

47

Co

pyr

igh

201

4 A

ccso

Gm

bHInterne Iteration, Streams, Filter/Map/Reduce

lc04_streams

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

48

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

49

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

50

Co

pyr

igh

201

4 A

ccso

Gm

bHEnde

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

51

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

52

Co

pyr

igh

201

4 A

ccso

Gm

bH

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>

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

53

Co

pyr

igh

201

4 A

ccso

Gm

bH

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>

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

54

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

55

Co

pyr

igh

201

4 A

ccso

Gm

bH

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>

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

56

Co

pyr

igh

201

4 A

ccso

Gm

bH

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 von Instanz von ToDoubleFunction

<Integer>

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

57

Co

pyr

igh

201

4 A

ccso

Gm

bH

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 von Instanz von ToDoubleFunction

<Integer>

Instanz von DoubleBinaryOperator

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

58

Co

pyr

igh

201

4 A

ccso

Gm

bHDie 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 von Instanz von ToDoubleFunction

<Integer>

Instanz von DoubleBinaryOperator

lazy lazy eager

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

59

Co

pyr

igh

201

4 A

ccso

Gm

bH

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 Operationis.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”.

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

60

Co

pyr

igh

201

4 A

ccso

Gm

bH

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 Operationis.forEach(l -> System.out.print(l + ", "));

// zweite terminale Operationint sum = is.reduce(0, (l1, l2) -> { return (l1 + l2); });

Laufzeitfehler daher bei der zweiten terminalen Operation!

Exception in thread "main" java.lang.IllegalStateEx ception: stream has already been operated uponat 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.

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

61

Co

pyr

igh

201

4 A

ccso

Gm

bH

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 - -

... ... ... ... ...

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

62

Co

pyr

igh

201

4 A

ccso

Gm

bH

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 ();

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

63

Co

pyr

igh

201

4 A

ccso

Gm

bHAgenda: Was kommt in Java 8 mit JSR 335?

Lambda-Ausdrücke

Verbesserte Typinferenz

Methodenreferenzen

Collections & Streams

Fehlerbehandlung

Funktionale InterfacesDefault-

Methoden

in

Interfacesjava.util.function

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

64

Co

pyr

igh

201

4 A

ccso

Gm

bHFehlerbehandlung in Streams

lc05_streams_errorhandling

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

65

Co

pyr

igh

201

4 A

ccso

Gm

bH

Error Handling in Streams (1/3)ohne Exception-Handling in try/catch

String[] txt = { "abc", "abcde", "abc" };

// Stream wird aufgebautStream<Character> s1 = Arrays.stream(txt).

map(t -> {// gezielte Exception fuer alle Strings mit Laenge > 3if (t.length()>3) throw new RuntimeException("test too long");return t.charAt(0);

});

// Stream wird konsumierts1.forEach( c -> System.out.print(c.charValue() + ",") );

Ausgabe: a, danach Exception (da abcde zu lange ist).

abc wird nicht mehr verarbeitet.

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

66

Co

pyr

igh

201

4 A

ccso

Gm

bH

Error Handling in Streams (2/3)Exception-Handling in der intermediären Operation

String[] txt = { "rst", "rstuv", "rst" };

// Stream wird aufgebautStream<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 konsumierts2.forEach(c -> { if (c!=null) System.out.print(c.charValue() + ","); });

Ausgabe: r und r

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

67

Co

pyr

igh

201

4 A

ccso

Gm

bH

Error Handling in Streams (3/3)Exception-Handling in der terminalen Operation

String[] txt = { "xyz", "vwxyz", "xyz" };

// Stream wird aufgebautStream<Character> s3 = Arrays.stream(txt).

map(t -> {if (t.length()>3) throw new RuntimeException("test too long");return t.charAt(0);

});

// Stream wird konsumierts3.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.

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

68

Co

pyr

igh

201

4 A

ccso

Gm

bHEnde

Image courtesy of phanlop88 / FreeDigitalPhotos.net

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

69

Co

pyr

igh

201

4 A

ccso

Gm

bHAgenda: Was kommt in Java 8 mit JSR 335?

Lambda-Ausdrücke

Verbesserte Typinferenz

Methodenreferenzen

Collections & Streams

Parallelisierung

Funktionale InterfacesDefault-

Methoden

in

Interfacesjava.util.function

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

70

Co

pyr

igh

201

4 A

ccso

Gm

bHWie kann man Programme überhaupt parallelisieren?

Schritt 1

Schritt 2

Schritt 3

Schritt 4

Schritt 5

Schritt 6

Variante 1: Parallelisierung des Datenflussesfo

r 1

... k

do

Schritt 1

Schritt 2

Schritt 3

Schritt 4

Schritt 5

Schritt 6

for

each

ele

men

t d

o in

par

alle

l 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

......

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

71

Co

pyr

igh

201

4 A

ccso

Gm

bHWie 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

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

72

Co

pyr

igh

201

4 A

ccso

Gm

bHWie 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!

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

73

Co

pyr

igh

201

4 A

ccso

Gm

bHFork-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

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

74

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

75

Co

pyr

igh

201

4 A

ccso

Gm

bH

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); });

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

76

Grenzen der Parallelisierung: Unterscheide zustandslose von zustandsbehafteten intermediären Operationen

Zustandslose intermediäreOperationen

� 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äreOperationen

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

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).

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

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);

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

79

Performance bei der Parallelisierung in Streams: Old Style vs. Seq. Streams vs. Parallele Streams

Image courtesy of phanlop88 / FreeDigitalPhotos.net

lc06_streams_parallel

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

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!

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

81

Co

pyr

igh

201

4 A

ccso

Gm

bH

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/2013PDF-Download hier:http://www.sigs-datacom.de/fachzeitschriften/javaspektrum/archiv/artikelansicht.html?tx_mwjournals_pi1[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/2012PDF-Download hier:

http://www.sigs-datacom.de/fachzeitschriften/javaspektrum/archiv/artikelansicht.html?tx_mwjournals_pi1[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

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

82

Co

pyr

igh

201

4 A

ccso

Gm

bH

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

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

Begeisterung für die

anspruchsvollen Aufgaben unserer Kunden

Individuelle

Kernsysteme

Beschleunigte

SoftwaretechnikTeam≡