Java : Lambda Ausdrücke

Die Lambdas oder auch Closures genannt, sind mit der Version 8 von Oracle Java dazu gekommen. Und bieten dem Entwickler einen zusätzlichen Funktionsumfang womit dieser noch weniger Code in noch kürzerer Zeit schreiben kann. Ob jedoch dieser Quellcode lesbarer und performanter als vorher ist schauen wir und am Ende des Beitrages an.

Beispiel mit einer ForEach Schleife

Hier nun ein paar kleine Beispiele anhand einer einfachen ForEach Schleife.

Gegeben ist immer folgende Liste:

Vor der Version 5 von Java musste die Schleife wiefolgt aussehen:

Ab der Version 5 konnte man dieses mit der Erweiterten ForEach Schleife deutlich kürzer schreiben:

Seit der Einführung der Lambdas könnte der Ausdruck wie folgt aussehen:

Performancevergleich

Wie performant ist das ganze nun im Vergleich zu einem „normalen“ Ausdruck?
Im nachfolgenden möchte ich nun die Performance mit einem einfachen Mittel messen, ich nehme vor dem starten der Methode einen Timestamp und danach einen Timestamp der Rest ist simple Mathematik.

MethodeDauer*
 simpleForEachBeforeJava5() 8,6ms.
 simpleForEachAfterJava5() 1,4ms.
 simpleForEachLambda() 36,6ms.

*Durchschnittswert nach 10 Durchläufen.

Neue Operationen an Listen

Neben der Methode „forEach“ existieren noch weitere Operationen, dabei unterscheidet man zwischen einer „intermediate operation“ und einer „terminal operation“.

Intermediate Operation

Eine „intermediate operation“ hat immer einen Rückgabewert in Form eines modifizierten Streams auf diesen können dann weitere Operationen ausgeführt werden.

filter

Mit der Methode „filter“ kann man wie es sich erahnen läßt einen Stream nach einem bestimmten Kriterum (Predicate) filtern.
Da die Methode „filter“ einen manipulierten Stream zurückliefert kann man nun mit der Methode „findAny“ ein Optional zurückliefern. Wenn die Methode jedoch nichts findet so wird kein NULL zurück gegeben sondern ein Optional jedoch ohne Value. D.h. entweder man prüft am Optional ob dieses einen Wert hat oder aber man liefert ein NULL zurück.

Folgender Test liefert immer ein Optional zurück.

Im nun folgenden Test wird nach einem Namen gesucht welcher nicht in der Liste enthalten ist.
Im „echten“ Leben kennt man jedoch die Liste nicht daher wird dieses programmatisch wie folgt gelöst:

Mit der Methode „orElse“ am Ende des Ausdrucks wird sichergestellt dass, wenn kein Treffer gefunden wurde NULL zurück gegeben wird.
Hier könnte auch ein beliebig anderes Objekt zurück geliefert werden.

Mehrfachprüfung

Möchte man in einem Ausdruck mehr als eine Prüfung durchführen, so erweitert man den Ausdruck um eine geschweifte Klammer um darin die prüfungen durchzuführen. Als Rückgabewert wird ein Boolean erwartet, „true“ wenn der Ausdruck zutrifft und „false“ wenn nicht.

map

Mit der Methode „map“ kann man aus einen Ergebnis der filter Methode oder aber aus der gesamten Liste (mit „stream“) ein neues Objekt erstellen und zurückliefern.

Es soll nun für jeden Namen aus der Liste ein Objekt Person erstellt werden:

Bevor es die Methode map gab wurde dieses wie folgt gelöst:

Mit der Methode map ist daraus nun ein einzeiliger Ausdruck geworden welcher wie folgt aussieht:

sorted

Die Methode „sorted“ gibt einem die Möglichkeit eine Collection oder Map nach einem oder mehrere Kriterien zu sortieren. Maps können auch nach dem Key oder Value sortiert werden.
Wollte man „damals“ eine einfache Liste mit String Werten sortieren so brauchte man nur

Ein String ist hier am einfachsten zu sortieren da der Comparator welcher für die Methode „sort“ herangezogen wird die Methode toString() aufruft.

Seit Java8 kann man dieses nun eleganter schreiben.

Es ist nun auch wieder ein einzeiliger Ausdruck geworden. Des Weiteren haben wir die ursprüngliche Liste nicht geändert und somit eine neue Liste mit werten erzeugt.

Eine Liste ist jedoch ein sehr einfaches Beispiel, wie das mit einer Map aussieht möchte ich nun an einem kleinen Beispiel erläutern:

 

Terminal Operation

Eine Terminal Operation steht immer am Ende der Pipeline und erzeugt bzw. liefert einen Wert. Wir haben bereits  sollche Terminal Operations im ersten Kapitel verwendet zbsp. collect(Collectors.toList());“ oder auch „findAny();“.

collect

Mit der Methode „collect“ wird das Ergebnis einer Intermediate Operation gesammelt und zbsp. in eine java.util.Collection geschrieben.

Es gibt auch die Möglichkeit die Werte Zu einer Zeichenkette zusammen zuführen, dieses ist ein beliebtes Beispiel denn in einer For Schleife müsste man zuletzt immer prüfen ob der Zähler sich am Ende befindet und dann das Trennzeichen nicht anzeigen.

Dieses wird nun deutlich vereinfacht:

Hier hat Google eine sehr gute Bibliothek erschaffen welche das noch mehr vereinfacht, zu finden ist diese im Maven Repository com.google.guava

findFirst

Wie die Bezeichnung es vermuten läßt, gibt die Methode findFirst den ersten Wert zurück. Als Rückgabe Wert erhält man ein Optional.

Gegeben sei also folgende java.util.List:

Der Name „Udo“ ist hier 2 mal vorhanden wir möchten jedoch nur den ersten Wert erhalten.

Mit der Methode FindFirst würde dieses wiefolgt gelöst werden:

Mit den „Boardmitteln“ von Java würde dieses nicht viel weniger Quellcode werden.

findAny

Die Methode findAny liefert in einem NICHT parellelen Stream den ersten Eintrag aus der Liste. Dieses ist jedoch nicht garantiert.

Mit Java8 wird dieses wiefolgt gelöst:

Wen der Stream leer ist (nicht NULL) dann liefert diese Methode ein „null“ zurück d.h. man muss einen NULL Check auf das erwartete Optional durchführen.

Oder man „hängt“ hier wieder die Methode „orElse“ an das Ergebnis um ein definiertes Objekt zu erhalten.

min & max

Mit den Methoden min & max kann man den kleinsten bzw. den größtmöglichen Zahlenwert aus einem Stream ermitteln.

Gegeben sei also folgende Liste mit ganzen Zahlen:

Die Methode „min“ erwartet einen Comparator welcher den Vergleich der Werte vornimmt.

Nun suchen wir den kleinsten Wert:

Das ermitteln des Maximalen Werts erfolgt ähnlich:

Wollte man in einer Liste den kleinsten bzw. größten Wert ohne die Verwendung von Lambda suchen so konnte man dieses wie folgt lösen:

Download

Das gesamte Eclipse Projekt mit allen JUnit Testfällen gibt es hier zum herrunterladen:

 

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.