Abkürzende Schreibweisen für Lambda-Ausdrücke
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.