SlideShare ist ein Scribd-Unternehmen logo
1 von 53
Downloaden Sie, um offline zu lesen
Java 8
mit Lambdas das hohe Lied des
Functional Programming singen
IPS-Expertenkreis
Dr. Hubert Austermeier
ORDIX AG
03.07.2014
ha@ordix.de
www.ordix.de
Motivation, Einführung
Definitionen zu Lambda Expressionss
Voraussetzungen: funktionale Schnittstellen
Noch kürzer: Referenzen auf Methoden/Konstruktoren
Streams: profitieren stark von Lambda Expressions
Agenda
Streams: profitieren stark von Lambda Expressions
Streams im Einsatz
Lösungen mittels Lambda Expressions
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 1
Es finden 3 String-Additionen und 2 toString() Konversionen statt
– auch dann, falls der Log Level auf Warning steht!
Probleme! Welche Probleme?
logger.info("x: " + x + ", y: " + y);
Keine Chance, diesen Code auf einem 8-Kern Rechner parallel laufen zu lassen
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 2
for (BusinessObj b : listOfBO)
b.doComplexWork();
Probleme…
saveButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveActions(e.getActionCommand());
}
});
Hässlich, einfach nur hässlich…
übrigens nicht nur für Entwickler, auch für die JVM!
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 3
Die zuvor gezeigten "Probleme" haben etwas gemeinsam:
mögliche Lösungen haben mit Funktionen zu tun;
Funktionen, die für eine Parameterübergabe taugen
Das führt zu Lambda Expressions, kurz Lambdas, welche die
bedeutendste Neuerung in Java 8 (seit März draußen) darstellen
Was kann helfen?
bedeutendste Neuerung in Java 8 (seit März draußen) darstellen
Die konkreten Lösungen schauen wir uns später an…
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 4
Lambdas sind seit langem auf der Agenda des Java-Fortschritts
benannt nach dem griechischem λ – und nach dem Lambda Kalkül
entwickelt in den 1930‘er Jahren zur Untersuchung von Funktionen
und deren Berechenbarkeit (A. Church, et al.)
Lambdas
Grundsätzliches
sollen das Prinzip des "Functional Programming" in Java befördern
bekannte, funktionale Programmiersprachen sind Lisp, Scheme, Haskell, …
Lambdas sollen u.a. die sperrigen, unleserlichen Anonymen Klassen
ablösen
werden zunehmend wichtig für das Thema "Multithreading“
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 5
Der Begriff Closure ist sehr verbreitet in der IT und bedeutet vereinfacht:
Code, der herumgereicht werden kann, z.B. an eine Methode, die
diesen Code verzögert ausführen kann deferred execution
Closure heißt es vielen Programmiersprachen (Scheme, Lisp, Scala, …),
Closure dort, Lambda hier
Closure heißt es vielen Programmiersprachen (Scheme, Lisp, Scala, …),
für Java wurde die Bezeichnung Lambda gewählt
Man findet auch den Begriff "Code as Data"
soll heißen, dass Code herumgereicht wird genauso wie Daten
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 6
In einem Blog Beitrag von James Gosling (Java Protagonist) findet
sich etwas zur Historie des Closure Themas in Java
(http://www.javaworld.com/#resources)
etwas Historie: Closures vs inner classes
Closures were left out of Java initially more because of
time pressures than anything else.
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 7
time pressures than anything else.
In the early days of Java the lack of closures was
pretty painful, and so inner classes were born:
an uncomfortable compromise that attempted to avoid
a number of hard issues. But as is normal in so
many design issues, the simplifications didn't really solve
any problems, they just moved them.
Beispiel in Java 8:
(a, b) -> a + b
symbolisiert die Funktion: Berechne die Summe von zwei Parametern
(der Typ von a und b ergibt sich aus dem Kontext,
dazu später mehr)
Wie sieht eine Lambda Expression denn nun aus?
dazu später mehr)
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 8
Motivation, Einführung
Definitionen zu Lambda Expressionss
Voraussetzungen: funktionale Schnittstellen
Noch kürzer: Referenzen auf Methoden/Konstruktoren
Streams: profitieren stark von Lambda Expressions
Agenda
Streams: profitieren stark von Lambda Expressions
Streams im Einsatz
Lösungen mittels Lambda Expressions
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 9
syntaktisch besteht einer Lambda Expression aus:
einer Liste von Parametern, durch Komma getrennt
einem Methodenrumpf
Zwischen Parameterliste und Methodenrumpf steht das "->" Symbol:
Syntax von Lambda Expressions
oder einfacher:
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 10
String[] names = {"Thomas", "Sebastian", "Uli", "Tobias", "Andreas"};
names.forEach((String element) -> { System.out.println(element); });
names.forEach(element -> System.out.println(element));
der Datentyp der Parameter wird aus dem Kontext abgeleitet
Zugriff auf Variablen des "umliegenden Scopes" ist möglich,
falls sie effektiv unveränderlich sind
der Modifier final ist mit Java 8 nicht mehr obligatorisch
weitere Definitionen
Gültigkeitsbereiche:
this bezieht sich auf die Instanz der Klasse,
in welcher Lambda Expression steht
super verweist auf die Oberklasse der Klasse,
in welcher Lambda Expression steht
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 11
Anonyme Klasse vs. Lambda Expression
String[] names = {"Thomas", "Sebastian", "Uli", "Tobias", "Andreas"};
// Anonyme Klasse
Arrays.sort(names, new Comparator<String>() {
@Override
public int compare(String name1, String name2) {
return name1.compareTo(name2);
}
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 12
}
});
// Lambda Expression
Arrays.sort(names, (name1, name2) -> name1.compareTo(name2));
Lambda Expressions können auch mehrere Anweisungen enthalten
der Anweisungsblock wird dann in geschweifte Klammern gesetzt
Mehrzeilige Lambda Expressions
Collections.sort(liste, (person1, person2) -> {
int c = person1.getVorname().compareTo(person2.getVorname());
if (c == 0)
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 13
if (c == 0)
c = person1.getNachname().compareTo(person2.getNachname());
return c;
});
Lambda Expressions können genutzt werden bei:
Variablen-Initialisierung oder -zuweisung
Argumentposition
Ergebnisrückgabe mit return
Rumpf eines größeren Lambda-Ausdrucks
Operand eines bedingten Ausdrucks (dreistelliger Operator ?:)
Lambda Expression dürfen wo stehen?
Operand eines bedingten Ausdrucks (dreistelliger Operator ?:)
generell überall, wo die Instanz eines Functional Interface stehen kann
im Gegensatz zu anonymen Klassen werden keine zusätzlichen
Bytecode-Dateien generiert!
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 14
Motivation, Einführung
Definitionen zu Lambda Expressionss
Voraussetzungen: funktionale Schnittstellen
Noch kürzer: Referenzen auf Methoden/Konstruktoren
Streams: profitieren stark von Lambda Expressions
Agenda
Streams: profitieren stark von Lambda Expressions
Streams im Einsatz
Lösungen mittels Lambda Expressions
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 15
sind Interfaces mit einer einzigen, abstrakten Methode
sog. SAM Interface (Single Abstract Method)
@FunctionalInterface markiert ein Functional Interface
Compiler kann damit prüfen, ob es valide ist
Functional Interfaces
sind Voraussetzung für Lambda Expressions, welche eine
kompakte Schreibweise bieten
Interfaces in Java 8 können default-Methoden implementieren!
(wichtig für Rückwärtskompabilität)
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 16
Functional Interfaces…
@FunctionalInterface
public interface MyFunctionalInterface {
void takeTime(LocalDateTime time);
default String timeFormatter(LocalDateTime time) {
return time.format(DateTimeFormatter.ISO_DATE);
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 17
return time.format(DateTimeFormatter.ISO_DATE);
}
}
Motivation, Einführung
Definitionen zu Lambda Expressionss
Voraussetzungen: funktionale Schnittstellen
Noch kürzer: Referenzen auf Methoden/Konstruktoren
Streams: profitieren stark von Lambda Expressions
Agenda
Streams: profitieren stark von Lambda Expressions
Streams im Einsatz
Lösungen mittels Lambda Expressions
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 18
Lambda Expression führen oft nur eine einzige Methode aus
Methoden Referenz bieten eine weitere, verkürzte Schreibweise
die Methode wird über Typ::Namen referenziert
neben dem Datentyp der Parameter, muss der Compiler auch
die Anzahl der Parameter aus dem Kontext ableiten
Methoden Referenzen
die Anzahl der Parameter aus dem Kontext ableiten
die Methode wird nicht aufgerufen, sondern referenziert!
Beispiel:
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 19
Integer[] numbers = {120 ,5, 90, 3, 1, 9, 14, 22, 2};
Arrays.stream(numbers).forEach(e -> System.out.println(e));
// geht einfacher mit Methoden Referenz
Arrays.stream(numbers).forEach(System.out::println);
syntaktisch besteht eine Methoden Referenz aus:
einem Receiver (Empfänger)
Name der statischen Methode oder Instanzmethode
durch “::“ verbunden
Syntax Methoden Referenzen
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 20
Syntax Beschreibung
Klasse::new Referenz auf einen Konstruktor
Klasse::statischeMethode Referenz auf eine statische Methode
Klasse::instanzMethode
Referenz auf eine Instanzmethode eines
beliebigen Objekts
Objekt::instanzMethode
Referenz auf eine Instanzmethode eines
bestimmten Objekts
Beispiele
// Methoden Referenz – statische Methode
Integer[] numbers = {120 ,5, 90, 3, 1, 9, 14, 22, 2};
Arrays.sort(numbers, Integer::compare);
//– nicht statische Methode
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 21
//– nicht statische Methode
String[] letters = {"V", "S", "C", "T", "A", "R", "H"};
Arrays.sort(letters, String::compareTo);
// - mittels eines bestimmten Objektes - bound
ComparisonProvider comparisonProvider = new ComparisonProvider();
personListe.sort(comparisonProvider::compareByName);
Beispiel: Klasse::new
// Konstruktor Referenz
String filesuffix = ".txt";
List<String> dataList = Arrays.asList("readme","releasenotes");
dataList.stream()
.map(StringBuilder::new)
.map(s->s.append(filesuffix));
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 22
Motivation, Einführung
Definitionen zu Lambda Expressionss
Voraussetzungen: funktionale Schnittstellen
Noch kürzer: Referenzen auf Methoden/Konstruktoren
Streams: profitieren stark von Lambda Expressions
Agenda
Streams: profitieren stark von Lambda Expressions
Streams im Einsatz
Lösungen mittels Lambda Expressions
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 23
neue, mächtige API in Java 8, um effizienter Collections einzusetzen
basieren stark auf Lambdas und Functional Interfaces
ein Stream speichert keine Daten
der Speicher besteht aus Collections, Arrays,…
Streams
Grundsätzliches
auf Streams finden Operationen (Methodenaufrufe) statt
es wird z.B. nicht iteriert über einen Stream
Stream Operationen ändern nicht ihre Quelle (z. B. eine List<…>)
sie geben neue Streams zurück bzw. erzeugen Ergebnisse
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 24
bislang mussten Entwickler vieles selbst programmieren:
Bspl.: "Iteration über ein Array und Elemente konkatenieren"
Stream API
Motivation
String[] strArr = new String[]{"Hallo", ", ", "Welt"};
StringBuilder satz = new StringBuilder("");
for (String wort: strArr) {
Nicht weiter schlimm, aber solcher Code ist z.B. schwer parallelisierbar!
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 25
for (String wort: strArr) {
satz.append(wort);
}
in der Stream API stecken viele implizite Algorithmen;
zum Iterieren gibt es beispielsweise die Methode: forEach
Iteration: forEach
String[] strArr = new String[]{"Hallo", ", ", "Welt"};
StringBuilder satz = new StringBuilder("");
Arrays.stream(strArr).forEach(satz::append);Arrays.stream(strArr).forEach(satz::append);
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 26
Stream-Operationen lassen sich in 3 Kategorien unterteilen:
Stream-Generierung (creation operation)
Stream-Transformation (intermediate operation)
werden 0..n mal angewendet
Stream Management
werden 0..n mal angewendet
liefern ihrerseits jeweils Streams zurück
Abschlussberechnung (terminal operation)
Sie werden auch in dieser Reihenfolge angewendet
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 27
Motivation, Einführung
Definitionen zu Lambda Expressionss
Voraussetzungen: funktionale Schnittstellen
Noch kürzer: Referenzen auf Methoden/Konstruktoren
Streams: profitieren stark von Lambda Expressions
Agenda
Streams: profitieren stark von Lambda Expressions
Streams im Einsatz
Lösungen mittels Lambda Expressions
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 28
einen Stream zu einer Collection (List, Set, Map,…) bekommt man
über die Methode stream()
Stream<String> s = stringSet.stream();
ein Array ist auf 2 Arten umwandelbar zu einem Stream :
Stream.of(anArray) liefert Stream für das gesamte Array
Arrays.stream(anArray, von, bis) liefert Stream für einen
Stream-Generierung (I/II)
Arrays.stream(anArray, von, bis) liefert Stream für einen
Abschnitt des Arrayes
Stream.empty() liefert einen leeren Stream
(kann nötig sein, falls leeres Ergebnis zurück zu geben ist)
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 29
Stream.generate(Math::random) liefert Stream von Zufallszahlen
weitere Java 8 API-Klassen liefern Streams als Resultat
um Zeilen einer Datei auszulesen:
Stream<String> lines = Files.lines(pFile);
Stream-Generierung (II/II)
Stream<String> lines = Files.lines(pFile);
um eine Suche durchzuführen und die passenden "Matches" zu erhalten:
Stream<String> words
= Pattern.compile(regExp).splitAsStream(contents);
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 30
eine Stream-Transformation liest Daten aus einem Stream und
packt modifizierte Daten in einen anderen Stream
Stream Transfomationen erfolgen häufig "lazy", d.h. erst wenn die
transformierten Daten benötigt werden, findet die Transformation statt
Stream-Transformation
die filter() Operation modifiziert einen Ursprungsdatenstrom,
in dem nur Elemente durchkommen, die ein gewisses Kriterium erfüllen
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 31
Suche nach oder Filtern von Elementen erforderte bislang
ein "aktives Suchen",
z.B. mittels einer Suchschleife wie "zählen aller Strings mit Länge > 2"
Suchen in Listen
String[] strArr = new String[]{"Hallo", ", ", "Welt"}; int count = 0;
for (String s : strArr) if (s.length > 2) count++;
Streams bieten dafür die Methode filter
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 32
Stream<String> strStream = Arrays.stream(strArr); int count = 0;
count = strSet.stream().filter(s -> s.length > 2).count();
um die einzelnen Elemente eines Streams zu transformieren,
rückt die Methode map() ins Blickfeld
wird aufgerufen mit eine Lambda Expression (oder Methoden Referenz)
diese bestimmt, wie der Typ des Transformationsergebnisses ist
Elemente umformen: map
diese bestimmt, wie der Typ des Transformationsergebnisses ist
map() erzeugt einen neuen Stream von Elementen
des gleichen Typs, falls lambda: Function(T, T) ist
vom Typ U, falls lambda: Function(T, U)
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 33
Aufgabenstellung: eine Liste von Wörtern umformen, so dass eine
Sequenz resultiert mit allen Wörtern in Kleinbuchstaben
Es greift der Mechanismus von map(): jedes Element wird einer
Transformation unterzogen und in einen neuen Stream gepackt
Beispiel: map
oder mittels Methoden Referenz
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014
List<String> wordList = ...;
Stream<String> words = wordList.stream();
Stream<String> lowercaseWords = words.map(s -> s.toLowerCase());
34
Stream<String> lowercaseWords = words.map(String::toLowerCase);
Ausgangslage: Elemente eines Streams sind so zu transformieren, dass
pro Element eine Container-Struktur entsteht (z.B. eine List<T>)
Wunsch: es soll keine Ineinanderschachtelung stattfinden, wie z.B.
Stream<List<T>>, sondern eine "flache" Struktur entstehen Stream<T>
Umformung Kaskadierung: flatMap
Lösung: die Methode flatMap() liefert genau das
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 35
die folgende Methode transformiert jeden String in einen
Stream<Character>:
BeispielS: flatMap
public static Stream<Character> characterStream(String s) {
List<Character> result = new ArrayList<>();
for (char c : s.toCharArray()) result.add(c);
return result.stream();
}
Ergebnis von characterStream("boot") ist der Stream ['b', 'o', ‘o', 't']
ein simples map() liefert eine verschachtelte Struktur
flatMap hingegen löst die innere Struktur und liefert einen "flachen" Stream
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 36
Stream<Stream<Character>> result = words.map(w -> characterStream(w));
}
Stream<Character> letters = words.flatMap(w -> characterStream(w));
Methoden, die eine endgültige Struktur oder einen Wert zurückgeben
sorgen dafür, dass alle Berechnungen, Transformationen,
Filterungen, etc. tatsächlich stattfinden
basieren hauptsächlich auf reduce() und collect()
Abschlussberechnung (terminal operation)
basieren hauptsächlich auf reduce() und collect()
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 37
um sukzessive, Element für Element zu rechnen und am
Ende ein Ergebnis zu liefern, eignet sich die Methode:
reduce()
es wird jeweils unter Hinzunahme eines weiteren Elementes
ein neues Zwischenergebnis gebildet
Einzelergebnisse aus Streams: reduce
ein neues Zwischenergebnis gebildet
reduce() hat bis zu 3 Argumente:
initialValue: Identitätswert; Operation mit diesem Wert liefert
identischen Wert, (0 bei Integer Addition)
accumulator: "addiert" ein Element zu einem (Zwischen)ergebnis
combiner: fasst zwei Zwischenergebnisse zu einem zusammen
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 38
einfaches Beispiel: "Berechne die Summe von n Zahlen"
Beispiele: reduce
Stream<Integer> values = ...;
// mit 1 Argument
Optional<Integer> sum = values.reduce((x, y) -> x + y)
// oder mit 2 Argumenten; Optional ist nicht mehr nötig!
Integer sum = values.reduce(0, (x, y) -> x + y)
bei einfachen Operationen ist wieder Methoden Referenz nutzbar
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 39
Integer sum = values.reduce(0, (x, y) -> x + y)
Stream<Integer> values = ...;
// Methoden-Referenz
Integer sum = values.reduce(0, Integer::sum)
anderes Beispiel: "Bilde die Summe der Längen aller Strings";
hier braucht man ein drittes Argument,
denn Teilergebnisse sind speziell zusammenzufassen
reduce mit combiner
int result = words.reduce(0,
(total, word) -> total + word.length(), // accumulator
(total1, total2) -> total1 + total2); // combiner
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 40
(total1, total2) -> total1 + total2); // combiner
wenn als Ergebnis eine komplexere Struktur erwartert wird, wie
z.B. ein HashSet, kann die Methode collect() genutzt werden
es wird jeweils unter Hinzunahme eines weiteren Elementes
ein bestehendes Zwischenergebnis erweitert!
Strukturergebnisse aus Streams: collect
collect() hat ebenfalls bis zu 3 Argumente:
supplier: Initialisierungsfunktion; liefert eine leere Struktur
accumulator: fügt ein Element einem (Zwischen)ergebnis hinzu
combiner: fügt ein Zwischenergebnis mit einem zweiten zusammen
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 41
Beispiel: "Bilde aus dem Stream von Strings eine HashSet-Struktur"
Beispiele: collect
HashSet<String> result =
words.collect(HashSet::new, HashSet::add, HashSet::addAll);
// ^ ^ ^
// supplier accumulator combiner
In der Praxis nutzt man Factory-Methoden aus der Collectors-Klasse
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 42
// für Standard Collections gibt es vorgefertigte Methoden
Set<String> hSResult = words.collect(Collectors.toSet());
Collectors-Klasse hat Angebote für alle gängigen Collections
collect...
List<String> lResult=
words.collect(Collectors.toList());
// oder etwas spezieller, nicht einfach Set, sondern TreeSet
TreeSet<String> tSResult =
words.collect(Collectors.toCollection(TreeSet::new));
Beispiel: String-Zusammenfassung:
"Bilde aus dem Stream von Strings einen Gesamtstring“
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 43
words.collect(Collectors.toCollection(TreeSet::new));
String result1 = words.collect(Collectors.joining());
// mit Trennzeichen zwischen Einzelstrings
String result2 = words.collect(Collectors.joining(", "));
Es soll eine Liste von Personen in eine Map transformiert werden,
so dass später für eine ID ein Name gefunden werden kann
(Annahme1: es gibt eine Person Klasse mit passenden Attributen)
(Annahme2: es gibt eine people Variable vom Typ Stream<Person>)
Elemente in eine Map packen mittels collect
// Collectors.toMap() hat zwei Argumente
// 1: wie komme ich an den key
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 44
// 1: wie komme ich an den key
// 2: was ist der value
Map<Integer, String> idToName = people.collect(
Collectors.toMap(Person::getId, Person::getName));
// value soll das Objekt sein
Map<Integer, Person> idToPerson = people.collect(
Collectors.toMap(Person::getId, Function.identity());
falls ein key mehr als einmal auftaucht, gibt es eine IllegalStateException
ein drittes Argument kann Kollisionsbehandlung übernehmen
Beispiel:
„Konstruktion einer Map für die Sprachen alle verfügbaren Locales.
Als key fungiert der Namen im default Locale ("German"),
welcher als value den lokalisierten Namen hat ("Deutsch").“
Kollisionen behandeln
welcher als value den lokalisierten Namen hat ("Deutsch").“
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 45
Stream<Locale> locales = Stream.of(Locale.getAvailableLocales());
Map<String, String> languageNames = locales.collect(
Collectors.toMap(
l -> l.getDisplayLanguage(),
l -> l.getDisplayLanguage(l),
(existingValue, newValue) -> existingValue));
Locales: ar_AE, ar_JO, ar_SY, hr_HR, fr_BE, es_PA, ...
Eine Liste von Elementen nach bestimmten Kriterien zu gruppieren,
ist eine häufig vorkommende Aufgabenstellung
daher gibt es dafür die spezielle Methode groupingBy
Beispiel: "Gruppiere alle Sprachen eines Landes“
Gruppierung durchführen: groupingBy
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 46
// groupingBy benötigt eine classifier function;
// hier: Locale::getCountry
Map<String, List<Locale>> countryToLocales =
locales.collect(Collectors.groupingBy(Locale::getCountry));
// Sprachen für die Schweiz:
List<Locale> swissLocales = countryToLocales.get("CH");
// Yields locales [it_CH, de_CH, fr_CH]
Motivation, Einführung
Definitionen zu Lambda Expressionss
Voraussetzungen: funktionale Schnittstellen
Noch kürzer: Referenzen auf Methoden/Konstruktoren
Streams: profitieren stark von Lambda Expressions
Agenda
Streams: profitieren stark von Lambda Expressions
Streams im Einsatz
Lösungen mittels Lambda Expressions
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 47
Wir erinnern uns, da war diese starre Anweisung:
Stattdessen können wir schreiben:
Lösungen…
logger.info( () -> "x: " + x + ", y: " + y );
logger.info("x: " + x + ", y: " + y);
und dürfen hoffen, dass das java.util.Logging um das Angebot eines
Functional Interface erweitert ist
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 48
// Auszug Logging API; neue log Methode mit Lambda;
// wird und nur bei Bedarf ausgewertet!
public void log(Level level, Supplier<String> msgSupplier) {
if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msgSupplier.get());
und was ist mit der Parallelisierung?
Da bietet die Stream API vielfältige Angebote, z.B.
Lösungen…
for (BusinessObj b : listOfBO)
b.doComplexWork();
Da bietet die Stream API vielfältige Angebote, z.B.
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 49
listOfBO.parllelStream().forEach(b.doComplexWork());
und schlussendlich unser hässlicher ActionListener?
Lösungen…
saveButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveActions(e.getActionCommand());
}
});
Da hilft eine simple (!!) Lambda Expression
Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 50
});
saveButton.addActionListener(
e-> saveActions(e.getActionCommand()));
Fazit
Lambda Expressions sind seit den Generics aus Java 5 die
gravierendste Neuerung in Java 8
Führen das Prinzip des "Functional Programming“ in die Java-Welt ein
Mit der Stream-API hat ORACLE/SUN eine leistungsfähige Innovation
Lambda Expression eröffnen ein neues Programmierprinzip
in Java, was durchaus als Bereicherung anzusehen ist
51Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014
Mit der Stream-API hat ORACLE/SUN eine leistungsfähige Innovation
des Collection Frameworks vorgenommen
unter starker Nutzung von Lambda Expressions
Zentrale Paderborn
Westernmauer 12 - 16
33098 Paderborn
Tel.: 05251 1063-0
Seminarzentrum Wiesbaden
Kreuzberger Ring 13
65205 Wiesbaden
Vielen Dank für Ihre Aufmerksamkeit!
65205 Wiesbaden
Tel.: 0611 77840-00
Zentrales Fax:
0180 1 67349 0
0180 1 ORDIX 0
Weitere Geschäftsstellen
in Köln, Münster und Neu-Ulm
E-Mail: info@ordix.de
Internet: http://www.ordix.de

Weitere ähnliche Inhalte

Ähnlich wie Java 8, mit Lambdas das hohe Lied des Functional Programming singen

6 - Sprachen des Semantic Web - RDF(S) Frameworks
6 - Sprachen des Semantic Web - RDF(S) Frameworks6 - Sprachen des Semantic Web - RDF(S) Frameworks
6 - Sprachen des Semantic Web - RDF(S) FrameworksSteffen Schloenvoigt
 
Dokumentenorientiere Datenbanken am Beispiel CouchDB
Dokumentenorientiere Datenbanken am Beispiel CouchDBDokumentenorientiere Datenbanken am Beispiel CouchDB
Dokumentenorientiere Datenbanken am Beispiel CouchDBMario Müller
 
The Lotus Code Cookbook
The Lotus Code CookbookThe Lotus Code Cookbook
The Lotus Code CookbookUlrich Krause
 
Fundamentale Muster in Java
Fundamentale Muster in JavaFundamentale Muster in Java
Fundamentale Muster in Javatutego
 
Ruby On Rails Einführung
Ruby On Rails EinführungRuby On Rails Einführung
Ruby On Rails EinführungReinhold Weber
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und ReflectionStefan Marr
 
Java Streams und Lambdas
Java Streams und LambdasJava Streams und Lambdas
Java Streams und LambdasNane Kratzke
 
Domain Driven Design in Rails
Domain Driven Design in RailsDomain Driven Design in Rails
Domain Driven Design in RailsAngelo Maron
 
Webinar - ABAP 7.50 Releaseabhängige Änderungen
Webinar - ABAP 7.50 Releaseabhängige ÄnderungenWebinar - ABAP 7.50 Releaseabhängige Änderungen
Webinar - ABAP 7.50 Releaseabhängige ÄnderungenCadaxo GmbH
 
Scala und Lift
Scala und LiftScala und Lift
Scala und Liftadesso AG
 
Einfuehrung in Apache Spark
Einfuehrung in Apache SparkEinfuehrung in Apache Spark
Einfuehrung in Apache SparkJens Albrecht
 
Addressroom
AddressroomAddressroom
Addressroomjoerg89
 
Interprozesskommunikation mit PHP
Interprozesskommunikation mit PHPInterprozesskommunikation mit PHP
Interprozesskommunikation mit PHPStephan Schmidt
 
Open Source Software zur Verarbeitung und Analyse von Metadatenmanagement
Open Source Software zur Verarbeitung und Analyse von MetadatenmanagementOpen Source Software zur Verarbeitung und Analyse von Metadatenmanagement
Open Source Software zur Verarbeitung und Analyse von MetadatenmanagementMagnus Pfeffer
 
IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007derDoc
 
elemente websolutions - Zusammenfassung T3DD09
elemente websolutions - Zusammenfassung T3DD09elemente websolutions - Zusammenfassung T3DD09
elemente websolutions - Zusammenfassung T3DD09elemente websolutions
 
Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013
Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013
Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013gedoplan
 

Ähnlich wie Java 8, mit Lambdas das hohe Lied des Functional Programming singen (20)

6 - Sprachen des Semantic Web - RDF(S) Frameworks
6 - Sprachen des Semantic Web - RDF(S) Frameworks6 - Sprachen des Semantic Web - RDF(S) Frameworks
6 - Sprachen des Semantic Web - RDF(S) Frameworks
 
Dokumentenorientiere Datenbanken am Beispiel CouchDB
Dokumentenorientiere Datenbanken am Beispiel CouchDBDokumentenorientiere Datenbanken am Beispiel CouchDB
Dokumentenorientiere Datenbanken am Beispiel CouchDB
 
The Lotus Code Cookbook
The Lotus Code CookbookThe Lotus Code Cookbook
The Lotus Code Cookbook
 
Fundamentale Muster in Java
Fundamentale Muster in JavaFundamentale Muster in Java
Fundamentale Muster in Java
 
SciflowWriter
SciflowWriterSciflowWriter
SciflowWriter
 
Ruby On Rails Einführung
Ruby On Rails EinführungRuby On Rails Einführung
Ruby On Rails Einführung
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und Reflection
 
Java Streams und Lambdas
Java Streams und LambdasJava Streams und Lambdas
Java Streams und Lambdas
 
Domain Driven Design in Rails
Domain Driven Design in RailsDomain Driven Design in Rails
Domain Driven Design in Rails
 
Scala und Lift
Scala und LiftScala und Lift
Scala und Lift
 
Webinar - ABAP 7.50 Releaseabhängige Änderungen
Webinar - ABAP 7.50 Releaseabhängige ÄnderungenWebinar - ABAP 7.50 Releaseabhängige Änderungen
Webinar - ABAP 7.50 Releaseabhängige Änderungen
 
Scala und Lift
Scala und LiftScala und Lift
Scala und Lift
 
Einfuehrung in Apache Spark
Einfuehrung in Apache SparkEinfuehrung in Apache Spark
Einfuehrung in Apache Spark
 
Addressroom
AddressroomAddressroom
Addressroom
 
Interprozesskommunikation mit PHP
Interprozesskommunikation mit PHPInterprozesskommunikation mit PHP
Interprozesskommunikation mit PHP
 
Open Source Software zur Verarbeitung und Analyse von Metadatenmanagement
Open Source Software zur Verarbeitung und Analyse von MetadatenmanagementOpen Source Software zur Verarbeitung und Analyse von Metadatenmanagement
Open Source Software zur Verarbeitung und Analyse von Metadatenmanagement
 
IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007
 
elemente websolutions - Zusammenfassung T3DD09
elemente websolutions - Zusammenfassung T3DD09elemente websolutions - Zusammenfassung T3DD09
elemente websolutions - Zusammenfassung T3DD09
 
Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013
Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013
Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013
 
Workshop: Besseres C#
Workshop: Besseres C#Workshop: Besseres C#
Workshop: Besseres C#
 

Java 8, mit Lambdas das hohe Lied des Functional Programming singen

  • 1. Java 8 mit Lambdas das hohe Lied des Functional Programming singen IPS-Expertenkreis Dr. Hubert Austermeier ORDIX AG 03.07.2014 ha@ordix.de www.ordix.de
  • 2. Motivation, Einführung Definitionen zu Lambda Expressionss Voraussetzungen: funktionale Schnittstellen Noch kürzer: Referenzen auf Methoden/Konstruktoren Streams: profitieren stark von Lambda Expressions Agenda Streams: profitieren stark von Lambda Expressions Streams im Einsatz Lösungen mittels Lambda Expressions Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 1
  • 3. Es finden 3 String-Additionen und 2 toString() Konversionen statt – auch dann, falls der Log Level auf Warning steht! Probleme! Welche Probleme? logger.info("x: " + x + ", y: " + y); Keine Chance, diesen Code auf einem 8-Kern Rechner parallel laufen zu lassen Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 2 for (BusinessObj b : listOfBO) b.doComplexWork();
  • 4. Probleme… saveButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { saveActions(e.getActionCommand()); } }); Hässlich, einfach nur hässlich… übrigens nicht nur für Entwickler, auch für die JVM! Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 3
  • 5. Die zuvor gezeigten "Probleme" haben etwas gemeinsam: mögliche Lösungen haben mit Funktionen zu tun; Funktionen, die für eine Parameterübergabe taugen Das führt zu Lambda Expressions, kurz Lambdas, welche die bedeutendste Neuerung in Java 8 (seit März draußen) darstellen Was kann helfen? bedeutendste Neuerung in Java 8 (seit März draußen) darstellen Die konkreten Lösungen schauen wir uns später an… Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 4
  • 6. Lambdas sind seit langem auf der Agenda des Java-Fortschritts benannt nach dem griechischem λ – und nach dem Lambda Kalkül entwickelt in den 1930‘er Jahren zur Untersuchung von Funktionen und deren Berechenbarkeit (A. Church, et al.) Lambdas Grundsätzliches sollen das Prinzip des "Functional Programming" in Java befördern bekannte, funktionale Programmiersprachen sind Lisp, Scheme, Haskell, … Lambdas sollen u.a. die sperrigen, unleserlichen Anonymen Klassen ablösen werden zunehmend wichtig für das Thema "Multithreading“ Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 5
  • 7. Der Begriff Closure ist sehr verbreitet in der IT und bedeutet vereinfacht: Code, der herumgereicht werden kann, z.B. an eine Methode, die diesen Code verzögert ausführen kann deferred execution Closure heißt es vielen Programmiersprachen (Scheme, Lisp, Scala, …), Closure dort, Lambda hier Closure heißt es vielen Programmiersprachen (Scheme, Lisp, Scala, …), für Java wurde die Bezeichnung Lambda gewählt Man findet auch den Begriff "Code as Data" soll heißen, dass Code herumgereicht wird genauso wie Daten Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 6
  • 8. In einem Blog Beitrag von James Gosling (Java Protagonist) findet sich etwas zur Historie des Closure Themas in Java (http://www.javaworld.com/#resources) etwas Historie: Closures vs inner classes Closures were left out of Java initially more because of time pressures than anything else. Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 7 time pressures than anything else. In the early days of Java the lack of closures was pretty painful, and so inner classes were born: an uncomfortable compromise that attempted to avoid a number of hard issues. But as is normal in so many design issues, the simplifications didn't really solve any problems, they just moved them.
  • 9. Beispiel in Java 8: (a, b) -> a + b symbolisiert die Funktion: Berechne die Summe von zwei Parametern (der Typ von a und b ergibt sich aus dem Kontext, dazu später mehr) Wie sieht eine Lambda Expression denn nun aus? dazu später mehr) Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 8
  • 10. Motivation, Einführung Definitionen zu Lambda Expressionss Voraussetzungen: funktionale Schnittstellen Noch kürzer: Referenzen auf Methoden/Konstruktoren Streams: profitieren stark von Lambda Expressions Agenda Streams: profitieren stark von Lambda Expressions Streams im Einsatz Lösungen mittels Lambda Expressions Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 9
  • 11. syntaktisch besteht einer Lambda Expression aus: einer Liste von Parametern, durch Komma getrennt einem Methodenrumpf Zwischen Parameterliste und Methodenrumpf steht das "->" Symbol: Syntax von Lambda Expressions oder einfacher: Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 10 String[] names = {"Thomas", "Sebastian", "Uli", "Tobias", "Andreas"}; names.forEach((String element) -> { System.out.println(element); }); names.forEach(element -> System.out.println(element));
  • 12. der Datentyp der Parameter wird aus dem Kontext abgeleitet Zugriff auf Variablen des "umliegenden Scopes" ist möglich, falls sie effektiv unveränderlich sind der Modifier final ist mit Java 8 nicht mehr obligatorisch weitere Definitionen Gültigkeitsbereiche: this bezieht sich auf die Instanz der Klasse, in welcher Lambda Expression steht super verweist auf die Oberklasse der Klasse, in welcher Lambda Expression steht Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 11
  • 13. Anonyme Klasse vs. Lambda Expression String[] names = {"Thomas", "Sebastian", "Uli", "Tobias", "Andreas"}; // Anonyme Klasse Arrays.sort(names, new Comparator<String>() { @Override public int compare(String name1, String name2) { return name1.compareTo(name2); } Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 12 } }); // Lambda Expression Arrays.sort(names, (name1, name2) -> name1.compareTo(name2));
  • 14. Lambda Expressions können auch mehrere Anweisungen enthalten der Anweisungsblock wird dann in geschweifte Klammern gesetzt Mehrzeilige Lambda Expressions Collections.sort(liste, (person1, person2) -> { int c = person1.getVorname().compareTo(person2.getVorname()); if (c == 0) Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 13 if (c == 0) c = person1.getNachname().compareTo(person2.getNachname()); return c; });
  • 15. Lambda Expressions können genutzt werden bei: Variablen-Initialisierung oder -zuweisung Argumentposition Ergebnisrückgabe mit return Rumpf eines größeren Lambda-Ausdrucks Operand eines bedingten Ausdrucks (dreistelliger Operator ?:) Lambda Expression dürfen wo stehen? Operand eines bedingten Ausdrucks (dreistelliger Operator ?:) generell überall, wo die Instanz eines Functional Interface stehen kann im Gegensatz zu anonymen Klassen werden keine zusätzlichen Bytecode-Dateien generiert! Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 14
  • 16. Motivation, Einführung Definitionen zu Lambda Expressionss Voraussetzungen: funktionale Schnittstellen Noch kürzer: Referenzen auf Methoden/Konstruktoren Streams: profitieren stark von Lambda Expressions Agenda Streams: profitieren stark von Lambda Expressions Streams im Einsatz Lösungen mittels Lambda Expressions Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 15
  • 17. sind Interfaces mit einer einzigen, abstrakten Methode sog. SAM Interface (Single Abstract Method) @FunctionalInterface markiert ein Functional Interface Compiler kann damit prüfen, ob es valide ist Functional Interfaces sind Voraussetzung für Lambda Expressions, welche eine kompakte Schreibweise bieten Interfaces in Java 8 können default-Methoden implementieren! (wichtig für Rückwärtskompabilität) Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 16
  • 18. Functional Interfaces… @FunctionalInterface public interface MyFunctionalInterface { void takeTime(LocalDateTime time); default String timeFormatter(LocalDateTime time) { return time.format(DateTimeFormatter.ISO_DATE); Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 17 return time.format(DateTimeFormatter.ISO_DATE); } }
  • 19. Motivation, Einführung Definitionen zu Lambda Expressionss Voraussetzungen: funktionale Schnittstellen Noch kürzer: Referenzen auf Methoden/Konstruktoren Streams: profitieren stark von Lambda Expressions Agenda Streams: profitieren stark von Lambda Expressions Streams im Einsatz Lösungen mittels Lambda Expressions Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 18
  • 20. Lambda Expression führen oft nur eine einzige Methode aus Methoden Referenz bieten eine weitere, verkürzte Schreibweise die Methode wird über Typ::Namen referenziert neben dem Datentyp der Parameter, muss der Compiler auch die Anzahl der Parameter aus dem Kontext ableiten Methoden Referenzen die Anzahl der Parameter aus dem Kontext ableiten die Methode wird nicht aufgerufen, sondern referenziert! Beispiel: Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 19 Integer[] numbers = {120 ,5, 90, 3, 1, 9, 14, 22, 2}; Arrays.stream(numbers).forEach(e -> System.out.println(e)); // geht einfacher mit Methoden Referenz Arrays.stream(numbers).forEach(System.out::println);
  • 21. syntaktisch besteht eine Methoden Referenz aus: einem Receiver (Empfänger) Name der statischen Methode oder Instanzmethode durch “::“ verbunden Syntax Methoden Referenzen Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 20 Syntax Beschreibung Klasse::new Referenz auf einen Konstruktor Klasse::statischeMethode Referenz auf eine statische Methode Klasse::instanzMethode Referenz auf eine Instanzmethode eines beliebigen Objekts Objekt::instanzMethode Referenz auf eine Instanzmethode eines bestimmten Objekts
  • 22. Beispiele // Methoden Referenz – statische Methode Integer[] numbers = {120 ,5, 90, 3, 1, 9, 14, 22, 2}; Arrays.sort(numbers, Integer::compare); //– nicht statische Methode Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 21 //– nicht statische Methode String[] letters = {"V", "S", "C", "T", "A", "R", "H"}; Arrays.sort(letters, String::compareTo); // - mittels eines bestimmten Objektes - bound ComparisonProvider comparisonProvider = new ComparisonProvider(); personListe.sort(comparisonProvider::compareByName);
  • 23. Beispiel: Klasse::new // Konstruktor Referenz String filesuffix = ".txt"; List<String> dataList = Arrays.asList("readme","releasenotes"); dataList.stream() .map(StringBuilder::new) .map(s->s.append(filesuffix)); Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 22
  • 24. Motivation, Einführung Definitionen zu Lambda Expressionss Voraussetzungen: funktionale Schnittstellen Noch kürzer: Referenzen auf Methoden/Konstruktoren Streams: profitieren stark von Lambda Expressions Agenda Streams: profitieren stark von Lambda Expressions Streams im Einsatz Lösungen mittels Lambda Expressions Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 23
  • 25. neue, mächtige API in Java 8, um effizienter Collections einzusetzen basieren stark auf Lambdas und Functional Interfaces ein Stream speichert keine Daten der Speicher besteht aus Collections, Arrays,… Streams Grundsätzliches auf Streams finden Operationen (Methodenaufrufe) statt es wird z.B. nicht iteriert über einen Stream Stream Operationen ändern nicht ihre Quelle (z. B. eine List<…>) sie geben neue Streams zurück bzw. erzeugen Ergebnisse Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 24
  • 26. bislang mussten Entwickler vieles selbst programmieren: Bspl.: "Iteration über ein Array und Elemente konkatenieren" Stream API Motivation String[] strArr = new String[]{"Hallo", ", ", "Welt"}; StringBuilder satz = new StringBuilder(""); for (String wort: strArr) { Nicht weiter schlimm, aber solcher Code ist z.B. schwer parallelisierbar! Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 25 for (String wort: strArr) { satz.append(wort); }
  • 27. in der Stream API stecken viele implizite Algorithmen; zum Iterieren gibt es beispielsweise die Methode: forEach Iteration: forEach String[] strArr = new String[]{"Hallo", ", ", "Welt"}; StringBuilder satz = new StringBuilder(""); Arrays.stream(strArr).forEach(satz::append);Arrays.stream(strArr).forEach(satz::append); Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 26
  • 28. Stream-Operationen lassen sich in 3 Kategorien unterteilen: Stream-Generierung (creation operation) Stream-Transformation (intermediate operation) werden 0..n mal angewendet Stream Management werden 0..n mal angewendet liefern ihrerseits jeweils Streams zurück Abschlussberechnung (terminal operation) Sie werden auch in dieser Reihenfolge angewendet Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 27
  • 29. Motivation, Einführung Definitionen zu Lambda Expressionss Voraussetzungen: funktionale Schnittstellen Noch kürzer: Referenzen auf Methoden/Konstruktoren Streams: profitieren stark von Lambda Expressions Agenda Streams: profitieren stark von Lambda Expressions Streams im Einsatz Lösungen mittels Lambda Expressions Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 28
  • 30. einen Stream zu einer Collection (List, Set, Map,…) bekommt man über die Methode stream() Stream<String> s = stringSet.stream(); ein Array ist auf 2 Arten umwandelbar zu einem Stream : Stream.of(anArray) liefert Stream für das gesamte Array Arrays.stream(anArray, von, bis) liefert Stream für einen Stream-Generierung (I/II) Arrays.stream(anArray, von, bis) liefert Stream für einen Abschnitt des Arrayes Stream.empty() liefert einen leeren Stream (kann nötig sein, falls leeres Ergebnis zurück zu geben ist) Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 29
  • 31. Stream.generate(Math::random) liefert Stream von Zufallszahlen weitere Java 8 API-Klassen liefern Streams als Resultat um Zeilen einer Datei auszulesen: Stream<String> lines = Files.lines(pFile); Stream-Generierung (II/II) Stream<String> lines = Files.lines(pFile); um eine Suche durchzuführen und die passenden "Matches" zu erhalten: Stream<String> words = Pattern.compile(regExp).splitAsStream(contents); Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 30
  • 32. eine Stream-Transformation liest Daten aus einem Stream und packt modifizierte Daten in einen anderen Stream Stream Transfomationen erfolgen häufig "lazy", d.h. erst wenn die transformierten Daten benötigt werden, findet die Transformation statt Stream-Transformation die filter() Operation modifiziert einen Ursprungsdatenstrom, in dem nur Elemente durchkommen, die ein gewisses Kriterium erfüllen Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 31
  • 33. Suche nach oder Filtern von Elementen erforderte bislang ein "aktives Suchen", z.B. mittels einer Suchschleife wie "zählen aller Strings mit Länge > 2" Suchen in Listen String[] strArr = new String[]{"Hallo", ", ", "Welt"}; int count = 0; for (String s : strArr) if (s.length > 2) count++; Streams bieten dafür die Methode filter Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 32 Stream<String> strStream = Arrays.stream(strArr); int count = 0; count = strSet.stream().filter(s -> s.length > 2).count();
  • 34. um die einzelnen Elemente eines Streams zu transformieren, rückt die Methode map() ins Blickfeld wird aufgerufen mit eine Lambda Expression (oder Methoden Referenz) diese bestimmt, wie der Typ des Transformationsergebnisses ist Elemente umformen: map diese bestimmt, wie der Typ des Transformationsergebnisses ist map() erzeugt einen neuen Stream von Elementen des gleichen Typs, falls lambda: Function(T, T) ist vom Typ U, falls lambda: Function(T, U) Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 33
  • 35. Aufgabenstellung: eine Liste von Wörtern umformen, so dass eine Sequenz resultiert mit allen Wörtern in Kleinbuchstaben Es greift der Mechanismus von map(): jedes Element wird einer Transformation unterzogen und in einen neuen Stream gepackt Beispiel: map oder mittels Methoden Referenz Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 List<String> wordList = ...; Stream<String> words = wordList.stream(); Stream<String> lowercaseWords = words.map(s -> s.toLowerCase()); 34 Stream<String> lowercaseWords = words.map(String::toLowerCase);
  • 36. Ausgangslage: Elemente eines Streams sind so zu transformieren, dass pro Element eine Container-Struktur entsteht (z.B. eine List<T>) Wunsch: es soll keine Ineinanderschachtelung stattfinden, wie z.B. Stream<List<T>>, sondern eine "flache" Struktur entstehen Stream<T> Umformung Kaskadierung: flatMap Lösung: die Methode flatMap() liefert genau das Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 35
  • 37. die folgende Methode transformiert jeden String in einen Stream<Character>: BeispielS: flatMap public static Stream<Character> characterStream(String s) { List<Character> result = new ArrayList<>(); for (char c : s.toCharArray()) result.add(c); return result.stream(); } Ergebnis von characterStream("boot") ist der Stream ['b', 'o', ‘o', 't'] ein simples map() liefert eine verschachtelte Struktur flatMap hingegen löst die innere Struktur und liefert einen "flachen" Stream Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 36 Stream<Stream<Character>> result = words.map(w -> characterStream(w)); } Stream<Character> letters = words.flatMap(w -> characterStream(w));
  • 38. Methoden, die eine endgültige Struktur oder einen Wert zurückgeben sorgen dafür, dass alle Berechnungen, Transformationen, Filterungen, etc. tatsächlich stattfinden basieren hauptsächlich auf reduce() und collect() Abschlussberechnung (terminal operation) basieren hauptsächlich auf reduce() und collect() Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 37
  • 39. um sukzessive, Element für Element zu rechnen und am Ende ein Ergebnis zu liefern, eignet sich die Methode: reduce() es wird jeweils unter Hinzunahme eines weiteren Elementes ein neues Zwischenergebnis gebildet Einzelergebnisse aus Streams: reduce ein neues Zwischenergebnis gebildet reduce() hat bis zu 3 Argumente: initialValue: Identitätswert; Operation mit diesem Wert liefert identischen Wert, (0 bei Integer Addition) accumulator: "addiert" ein Element zu einem (Zwischen)ergebnis combiner: fasst zwei Zwischenergebnisse zu einem zusammen Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 38
  • 40. einfaches Beispiel: "Berechne die Summe von n Zahlen" Beispiele: reduce Stream<Integer> values = ...; // mit 1 Argument Optional<Integer> sum = values.reduce((x, y) -> x + y) // oder mit 2 Argumenten; Optional ist nicht mehr nötig! Integer sum = values.reduce(0, (x, y) -> x + y) bei einfachen Operationen ist wieder Methoden Referenz nutzbar Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 39 Integer sum = values.reduce(0, (x, y) -> x + y) Stream<Integer> values = ...; // Methoden-Referenz Integer sum = values.reduce(0, Integer::sum)
  • 41. anderes Beispiel: "Bilde die Summe der Längen aller Strings"; hier braucht man ein drittes Argument, denn Teilergebnisse sind speziell zusammenzufassen reduce mit combiner int result = words.reduce(0, (total, word) -> total + word.length(), // accumulator (total1, total2) -> total1 + total2); // combiner Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 40 (total1, total2) -> total1 + total2); // combiner
  • 42. wenn als Ergebnis eine komplexere Struktur erwartert wird, wie z.B. ein HashSet, kann die Methode collect() genutzt werden es wird jeweils unter Hinzunahme eines weiteren Elementes ein bestehendes Zwischenergebnis erweitert! Strukturergebnisse aus Streams: collect collect() hat ebenfalls bis zu 3 Argumente: supplier: Initialisierungsfunktion; liefert eine leere Struktur accumulator: fügt ein Element einem (Zwischen)ergebnis hinzu combiner: fügt ein Zwischenergebnis mit einem zweiten zusammen Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 41
  • 43. Beispiel: "Bilde aus dem Stream von Strings eine HashSet-Struktur" Beispiele: collect HashSet<String> result = words.collect(HashSet::new, HashSet::add, HashSet::addAll); // ^ ^ ^ // supplier accumulator combiner In der Praxis nutzt man Factory-Methoden aus der Collectors-Klasse Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 42 // für Standard Collections gibt es vorgefertigte Methoden Set<String> hSResult = words.collect(Collectors.toSet());
  • 44. Collectors-Klasse hat Angebote für alle gängigen Collections collect... List<String> lResult= words.collect(Collectors.toList()); // oder etwas spezieller, nicht einfach Set, sondern TreeSet TreeSet<String> tSResult = words.collect(Collectors.toCollection(TreeSet::new)); Beispiel: String-Zusammenfassung: "Bilde aus dem Stream von Strings einen Gesamtstring“ Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 43 words.collect(Collectors.toCollection(TreeSet::new)); String result1 = words.collect(Collectors.joining()); // mit Trennzeichen zwischen Einzelstrings String result2 = words.collect(Collectors.joining(", "));
  • 45. Es soll eine Liste von Personen in eine Map transformiert werden, so dass später für eine ID ein Name gefunden werden kann (Annahme1: es gibt eine Person Klasse mit passenden Attributen) (Annahme2: es gibt eine people Variable vom Typ Stream<Person>) Elemente in eine Map packen mittels collect // Collectors.toMap() hat zwei Argumente // 1: wie komme ich an den key Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 44 // 1: wie komme ich an den key // 2: was ist der value Map<Integer, String> idToName = people.collect( Collectors.toMap(Person::getId, Person::getName)); // value soll das Objekt sein Map<Integer, Person> idToPerson = people.collect( Collectors.toMap(Person::getId, Function.identity());
  • 46. falls ein key mehr als einmal auftaucht, gibt es eine IllegalStateException ein drittes Argument kann Kollisionsbehandlung übernehmen Beispiel: „Konstruktion einer Map für die Sprachen alle verfügbaren Locales. Als key fungiert der Namen im default Locale ("German"), welcher als value den lokalisierten Namen hat ("Deutsch").“ Kollisionen behandeln welcher als value den lokalisierten Namen hat ("Deutsch").“ Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 45 Stream<Locale> locales = Stream.of(Locale.getAvailableLocales()); Map<String, String> languageNames = locales.collect( Collectors.toMap( l -> l.getDisplayLanguage(), l -> l.getDisplayLanguage(l), (existingValue, newValue) -> existingValue)); Locales: ar_AE, ar_JO, ar_SY, hr_HR, fr_BE, es_PA, ...
  • 47. Eine Liste von Elementen nach bestimmten Kriterien zu gruppieren, ist eine häufig vorkommende Aufgabenstellung daher gibt es dafür die spezielle Methode groupingBy Beispiel: "Gruppiere alle Sprachen eines Landes“ Gruppierung durchführen: groupingBy Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 46 // groupingBy benötigt eine classifier function; // hier: Locale::getCountry Map<String, List<Locale>> countryToLocales = locales.collect(Collectors.groupingBy(Locale::getCountry)); // Sprachen für die Schweiz: List<Locale> swissLocales = countryToLocales.get("CH"); // Yields locales [it_CH, de_CH, fr_CH]
  • 48. Motivation, Einführung Definitionen zu Lambda Expressionss Voraussetzungen: funktionale Schnittstellen Noch kürzer: Referenzen auf Methoden/Konstruktoren Streams: profitieren stark von Lambda Expressions Agenda Streams: profitieren stark von Lambda Expressions Streams im Einsatz Lösungen mittels Lambda Expressions Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 47
  • 49. Wir erinnern uns, da war diese starre Anweisung: Stattdessen können wir schreiben: Lösungen… logger.info( () -> "x: " + x + ", y: " + y ); logger.info("x: " + x + ", y: " + y); und dürfen hoffen, dass das java.util.Logging um das Angebot eines Functional Interface erweitert ist Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 48 // Auszug Logging API; neue log Methode mit Lambda; // wird und nur bei Bedarf ausgewertet! public void log(Level level, Supplier<String> msgSupplier) { if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msgSupplier.get());
  • 50. und was ist mit der Parallelisierung? Da bietet die Stream API vielfältige Angebote, z.B. Lösungen… for (BusinessObj b : listOfBO) b.doComplexWork(); Da bietet die Stream API vielfältige Angebote, z.B. Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 49 listOfBO.parllelStream().forEach(b.doComplexWork());
  • 51. und schlussendlich unser hässlicher ActionListener? Lösungen… saveButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { saveActions(e.getActionCommand()); } }); Da hilft eine simple (!!) Lambda Expression Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 50 }); saveButton.addActionListener( e-> saveActions(e.getActionCommand()));
  • 52. Fazit Lambda Expressions sind seit den Generics aus Java 5 die gravierendste Neuerung in Java 8 Führen das Prinzip des "Functional Programming“ in die Java-Welt ein Mit der Stream-API hat ORACLE/SUN eine leistungsfähige Innovation Lambda Expression eröffnen ein neues Programmierprinzip in Java, was durchaus als Bereicherung anzusehen ist 51Java 8 - Lambda Expressions, IPS Expertenkreis, 03.07.2014 Mit der Stream-API hat ORACLE/SUN eine leistungsfähige Innovation des Collection Frameworks vorgenommen unter starker Nutzung von Lambda Expressions
  • 53. Zentrale Paderborn Westernmauer 12 - 16 33098 Paderborn Tel.: 05251 1063-0 Seminarzentrum Wiesbaden Kreuzberger Ring 13 65205 Wiesbaden Vielen Dank für Ihre Aufmerksamkeit! 65205 Wiesbaden Tel.: 0611 77840-00 Zentrales Fax: 0180 1 67349 0 0180 1 ORDIX 0 Weitere Geschäftsstellen in Köln, Münster und Neu-Ulm E-Mail: info@ordix.de Internet: http://www.ordix.de