Was sind Lambda Ausdrücke (lambda expressions)?v.8.0
Nur selten oder gar nicht wiederverwendete Klassen werden in Java häufig und gerne als anonyme Klassen geschrieben. Das gängigste Beispiel dürfte die Verwendung eines einfachen ActionListeners sein, der z.B. die Funktionalität eines Buttons steuert:
JButton butt = new JButton("Klick"); butt.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Button angeklickt"); } });
Die hier deklarierte anonyme Klasse implementiert das Interface
ActionListener
, das nur eine einzige Methode
besitzt. Seit Java 8.0 werden solche Interfaces mit genau einer abstrakten
Methode als funktionale Interfaces bezeichnet. Um deren
Methoden zu nutzen, können ab Java 8.0 sog. Lambda
Ausdrücke eingesetzt werden. Das obige Beispiel kann
hiermit auf die folgende Weise umformuliert werden:
butt.addActionListener(e -> {System.out.println("Button angeklickt");});
Es fällt auf, dass hier als Argument der Methode addActionListener()
keine vollständige Objektbildung mit new
mehr
erfolgt. Statt dessen werden der (beliebige) Bezeichner des
Methodenarguments und die Anweisungen innerhalb der
Parameterklammern von actionPerformed()
getrennt
von einem Pfeiloperator ('->') notiert. Es wird also eine
Kurzform der vollständigen Methodenimplementierung als
Parameter der aufgerufenen Methode actionPerformed()
angegeben.
Dies kann auch mit mehreren Parametern (einer Methode) erfolgen, nicht jedoch bei anonymen Klassen oder Interfaces, die mehrere Methoden enthalten, da die identifizierende Methodensignatur ja nicht notiert wird. Besitzt eine Methode keinen Parameter, so werden lediglich die leeren runden Klammern notiert:
public class LambdaHello { interface Printer { void print(); } public static void main(String[] args) { Printer p = () -> System.out.println("Hallo Welt!"); p.print(); // "Hallo Welt!" } }
Man erkennt hier, dass Objektbildung und Speicherung in einer
Variablen, sowie Methodenimplementierung im einfachsten Fall
gerade einmal eine Zeile benötigen.
Das folgende
Beispiel zeigt wie dies mit der Definition eines eigenen
Interfaces, zwei Methodenparametern und zwei Anweisungen
funktioniert:
public class LambdaPrintTest { interface Printer { public void print(String s, String t); } public static void main(String[] args) { Printer p = (s, t) -> { t = t.toUpperCase(); System.out.println(s + " " + t); }; p.print("Hallo", "Welt"); // Hallo WELT } }
Sollen mehrere Anweisungen in der Methode ausgeführt
werden, so werden sie in geschweifte Klammern eingeschlossen und
jeweils durch Semikolon abgeschlossen. Bei nur einer Anweisung
kann der Einschluss in Klammern auch entfallen.
Besitzt die
Methode einen Rückgabewert, so wird dieser als letztes
notiert, ebenfalls durch Semikolon abgeschlossen:
public class LambdaCalculateTest { interface Rectangle { public double getArea(double length, double width); } public static void main(String[] args) { Rectangle rect = (l, w) -> { l*=2; w*=3; return l * w; }; System.out.println("Flaeche: " + rect.getArea(4, 3)); } }
Neben der vereinfachten Schreibweise einer anonymen Klasse
erlauben Lambda-Ausdrücke auch andere
Zugriffsberechtigungen auf Variablen. So kann innerhalb eines
Lambda-Ausdrucks direkt auf in der gleichen Codeebene
deklarierte Variablen zugegriffen werden, sofern diese final
deklariert oder zumindest effektiv final
sind. Im
folgenden Fall kann deshalb auf die explizite final
-Deklaration
von multi
verzichtet werden.
public class LambdaCalculateTest { interface Rectangle { public double getArea(double length, double width); } public static void main(String[] args) { double multi = 3; Rectangle rect = (l, w) -> { l*=multi; w*=multi; return l * w; }; System.out.println("Flaeche:" + rect.getArea(4, 3)); } }
Allerdings sollte in solchen Fällen vorsichtshalber nicht
auf eine final
-Deklaration verzichtet werden, denn
ein Code wie der folgende ist nicht möglich:
//... double multi = 3; multi = 8; Rectangle rect = (l, w) -> { l*=multi; w*=multi; return l * w; }; // Fehler //...
Quellen
http://www.tutego.de/blog/javainsel/2014/03/java-8-umgebung-lambda-ausdruecke-variablenzugriffe/