PDF Handout 4x4

Werbung
Funktionale vs. Imperative Programmierung
Imperative Konzepte
Ausführen von Anweisungen
Zustand (z.B. Felder)
Änderbare Datentypen
Fokus auf Datenstrukturen
Fokus auf das “wie”
13. Funktionale Konzepte in Java
Funktionale Programmierung, Lambda Ausdrücke, Datenströme,
Pipelines
Funktionale Konzepte
Evaluierung von Ausdrücken
Kein Zustand
Immutable Datentypen
Fokus auf Datenströme
Fokus auf das “was”
326
325
Beispiel: Einlesen von Daten - Imperativ
Beispiel: Einlesen von Daten - Funktional
try (BufferedReader br=new BufferedReader(new FileReader("daten.csv"))){
LinkedList<Messwert> resultat = new LinkedList<>();
br.readLine();
String zeile ;
while (( zeile = br.readLine()) != null){
Messwert m = new Messwert(zeile);
resultat .add(m);
}
return resultat ;
}
try (Stream<String> stream = Files.lines(Paths.get("daten.csv" ))) {
327
return stream.skip (1). map(Messwert::new).collect(toList ());
}
328
Streams - Datenströme
Operationen auf Datenströmen: Map
In Java sind Streams die Basis für funktionale Programmierung.
Quellen von Datenströmen:
Map: Anwenden von Funktionen auf den einzelnen Elementen des
Streams
Dateien
Arrays
Datenstrukturen
Mathematische Berechnungen
Erstellen neuer Objekte basierend auf den existierenden
Elementen.
...
...
Beispiel
Beispiel
Stream<String> stream = Files.lines (...))
map(Messwert::new)
330
329
Operationen auf Datenströmen: Reduce
Beispiel: Suchen von Daten - Imperativ
Reduce: Aggregierung der einzelnen Elemente eines Datenstroms
zu einem einzelnen Wert.
List<Messwert> daten = leseCsvDaten();
Koordinate ref = leseKoordinate();
Statistische Aggregationen
Ablegen der Elemente in Datenstrukturen
for (Messwert m : daten){
if (m.position.naheBei(ref)){
System.out.println(m. originalZeile );
}
}
...
Beispiel
collect ( toList ())
331
332
Beispiel: Suchen von Daten - Funktional
Operationen auf Datenströmen: Filter
Filter: Herausfiltern einzelner Elemente des Streams.
List<Messwert> daten = leseCsvDaten();
Koordinate ref = leseKoordinate();
Illegale Werte entfernen
Auswahl von Werten basierend auf Anfragen
daten.stream()
. filter (m −> ref.naheBei(m.position))
. forEach(System.out::println );
...
Beispiel
filter (m −> ref.naheBei(m.position))
334
333
Operationen auf Datenströmen: Seiteneffekte
Funktionalität als Parameter
Seiteneffekte: Der nicht-funktionale Aspekt: Ausführen von
beliebigen Operationen aufgrund einzelner Elemente.
Operationen auf dem Stream haben Funktionalität (Code) als
Parameter, anstelle von Daten
Input/Ouput
Datenstrukturen updaten
Möglichkeiten, Funktionalität zu übergeben:
“lose” Code-Stücke
Referenzen auf Methoden
Referenzen auf Konstruktoren
...
Beispiel
Wie können wir dies bewerkstelligen?
forEach(System.out::println)
335
336
Lambda Ausdrücke
Lambda Ausdrücke
Lambda Ausdrücke sind im Wesentlichen Methoden ohne Namen.
Lambda Ausdruck
(double a, double b, double c) −> {
return b∗b − 4∗a∗c;
}
Normale Methode
double diskriminante(double a, double b, double c){
return b∗b − 4∗a∗c;
}
Ohne explizite Typdeklaration der Parameter
(a, b, c) −> {
return b∗b − 4∗a∗c;
}
Gleichwertiger Lambda Ausdruck
(double a, double b, double c) −> {
return b∗b − 4∗a∗c;
}
Mit einem einzelnen Ausdruck statt einem Body
(a, b, c) −> b∗b − 4∗a∗c
337
Lambda Ausdruck im Beispiel
338
Referenzen auf Methoden
Beispiel
Um eine Methode auf einem Objekt auszuführen, schreiben wir:
filter (m −> ref.naheBei(m.position))
objekt.methode()
Die Methode filter erwartet eine Methode als Parameter, welche einen
Messwert entgegennimmt, und einen boolean zurueckgibt.
m ist ein Parameter vom Typ Messwert
Um eine Referenz auf eine Methode auf einem Objekt anzugeben
ohne diese auszuführen, schreiben wir:
X
ref.naheBei(m.position) ist ein einzelner booleanAusdruck
X
objekt::methode
Die Variable ref aus dem definierenden Kontext ist zugänglich, solange sie
effektiv konstant (final) ist.
339
340
Referenzen auf statische Methoden
Referenz auf eine Methode im Beispiel
Um eine statische Methode auszuführen, schreiben wir:
Beispiel
Klasse.methode()
forEach(System.out::println)
Die Methode forEach erwartet eine Methode, welche nichts zurück gibt und ein
Argument vom Typ Messwert akzeptiert.
Um eine Referenz auf eine statische Methode anzugeben,
schreiben wir:
Die Methode println auf Objekt out erfüllt diese Eigenschaften.
Klasse::methode
X
341
342
Referenzen auf Konstruktoren
Referenz auf einen Konstruktor im Beispiel
Um einen Konstruktur einer Klasse auszuführen, schreiben wir:
Beispiel
new Klasse()
map(Messwert::new)
Um eine Referenz auf einen Konstruktor anzugeben ohne das
Objekt dabei zu erstellen, schreiben wir:
Die Methode map erwartet eine Methode, welche ein Objekt eines gewissen
Datentyps zurueckgibt (egal welcher, solange immer der gleiche) und ein
Argument vom Typ String akzeptiert.
Klasse::new
Der Konstruktor der Klasse Messwert erfüllt diese Eigenschaft.
343
X
344
Vor- und Nachteile von Funktionaler Programmierung
Weniger fehleranfällig
Einfacher zu unterhalten
Neue Sprachkonzepte zu lernen
Ermöglicht elegante
Programmierung
Ausführungsdetails unbekannt
Nicht abhängig von spezifischer
Architektur
Aufgesetzt auf imperativer Sprache
345
Herunterladen