Lambda-Ausdrücke haben wie Methoden mögliche Parameter und Rückgabe. Die Java-Grammatik für die Schreibweise von Lambda-Ausdrücken sieht ein paar syntaktische Abkürzungen vor, dir wir uns nun anschauen wollen.
Typinferenz
Der Java-Compiler kann viele Typen aus dem Kontext ablesen, was Typ-Inferenz genannt wird. Wir kennen so etwas vom Diamanten, wenn wir schreiben List<String> list = new ArrayList<>();.
Statt
Comparator<String> c = (String s1, String s2) -> { return s1.trim().compareTo( s2.trim() ); };
erlaubt der Compiler auch die Abkürzung:
Comparator<String> c = (s1, s2) -> { return s1.trim().compareTo( s2.trim() ); };
Die Parameterliste enthält also deklarierte Parametertypen oder inferred-Typen. Eine Mischung ist nicht erlaubt, der Compiler blockt so etwas wie (String s1, s2) oder (s1, String s2) mit einem Fehler ab.
Lambda-Rumpf ist entweder einzelner Ausdruck oder Block
Besteht der Rumpf eines Lambda-Ausdrucks nur aus einem einzelnen Ausdruck, kann eine verkürzte Schreibweise die Block-Klammern und das Semikolon einsparen. Statt
‚(‚ Parameter ‚)‘ ‚->‘ ‚{‚ Anweisungen; ‚}‘
heißt es dann
‚(‚ Parameter ‚)‘ ‚->‘ Ausdruck
Lambda-Ausdrücke mit einer return–Anweisung im Rumpf kommen häufig vor (es entspricht den typischen Funktionen). Da ist es eine willkommene Verkürzung, wenn die abgekürzte Syntax für Lambda-Ausdrücke lediglich den Ausdruck fordert, der dann die Rückgabe bildet.
Drei Beispiele:
Lange Schreibweise |
Abkürzung |
(s1, s2) -> { return s1.trim().compareTo( s2.trim() ); } |
(s1, s2) -> s1.trim().compareTo( s2.trim() ) |
(a, b) -> { return a + b; } |
(a, b) -> a + b |
() -> { System.out.println(); } |
() -> System.out.println() |
Ausdrücke können in Java auch zu void ausgewertet werden, sodass ohne Probleme ein Aufruf wie System.out.println() in der kompakten Schreibweise ohne Block gesetzt werden kann.
Ob Lambda-Ausdrücke eine Rückgabe geben, drücken zwei Begriffe aus:
· Der Rumpf kann in Anweisungen enden, die nichts zurück geben. Das nennt sich void-kompatibel.
· Der Rumpf beendet den Block mit einer return-Anweisung, die einen Wert zurückgibt. Das nennt sich Wert-kompatibel.
Eine Mischung aus void- und Wert-kompatibel ist nicht erlaubt und führt wie bei Methoden zu einem Compilerfehler.[1]
Einzelner Identifizierer statt Parameterliste und Klammern
Besteht die Parameterliste nur aus einem einzelnen Identifizierer und ist der Typ durch Typ-Inferenz klar, können die runden Klammen wegfallen.
Lange Schreibweise |
Typen inferred |
Vollständig abgekürzt |
(Sting s) -> s.length() |
(s) -> s.length() |
s -> s.length() |
(int i) -> Math.abs( i ) |
(i) -> Math.abs( i ) |
i -> Math.abs( i ) |
Kommen alle Abkürzungen zusammen, lässt sich etwa die Hälfe einsparen. Aus (int i) -> { return Math.abs( i ); } wird dann i -> Math.abs( i ).
[1] Wohl aber gibt es wie bei { throw new RuntimeException(); } Ausnahmen, bei denen Lambda-Ausdrücke beides sind.