Java Lambda-Ausdrücke

Java 8 新特性Neue Funktionen in Java 8


Lambda-Ausdrücke, auch als Closures bekannt, sind das wichtigste neue Feature, das die Veröffentlichung von Java 8 vorangetrieben hat.

Lambda ermöglicht es, eine Funktion als Parameter an eine Methode zu übergeben (Funktionen werden als Argumente an Methoden übergeben).

Die Verwendung von Lambda-Ausdrücken kann den Code prägnanter und kompakter machen.

Syntax

Das Syntaxformat eines Lambda-Ausdrucks ist wie folgt:

(Parameter) -> Ausdruckoder(Parameter) ->{ Anweisungen; }

parametersist die Parameterliste,expressionoder{ statements; }ist der Rumpf des Lambda-Ausdrucks. Wenn es nur einen Parameter gibt, können die Klammern weggelassen werden; wenn es keine Parameter gibt, sind leere Klammern weiterhin erforderlich.

Nachfolgend sehen Sie ein einfaches Beispiel, das die Verwendung eines Lambda-Ausdrucks zur Berechnung der Summe zweier Zahlen zeigt:

Beispiel

// Verwendung eines Lambda-Ausdrucks zur Berechnung der Summe zweier Zahlen
MathOperation addition = (a, b) -> a + b;

// Aufrufen des Lambda-Ausdrucks
int result = addition.operation(5, 3);
System.out.println("5 + 3 = " + result);

Im obigen Beispiel ist MathOperation eine funktionale Schnittstelle, die eine abstrakte Methode operation enthält. Der Lambda-Ausdruck(a, b) -> a + bimplementiert diese abstrakte Methode und repräsentiert die Operation der Addition der beiden Parameter.

Lambda-Ausdrücke können in verschiedenen Szenarien verwendet werden, darunter Sammlungsoperationen, Ereignisbehandlung usw. Nachfolgend ein Beispiel für die Verwendung eines Lambda-Ausdrucks zum Iterieren über eine Liste:

Beispiel

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

// Verwendung eines Lambda-Ausdrucks zum Iterieren über eine Liste
names.forEach(name -> System.out.println(name));

Lambda-Ausdrücke führen einen funktionaleren Programmierstil in Java ein, wodurch der Code prägnanter und lesbarer wird. Sie sind eine wichtige Verbesserung der funktionalen Programmierung in Java 8.


Wichtige Features

Prägnanz

Lambda-Ausdrücke bieten eine prägnantere Syntax, die besonders für funktionale Schnittstellen geeignet ist. Im Vergleich zu traditionellen anonymen inneren Klassen machen Lambda-Ausdrücke den Code kompakter und reduzieren Boilerplate-Code.

Beispiel

// Traditionelle anonyme innere Klasse
Runnable runnable1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello World!");
    }
};

// Verwendung eines Lambda-Ausdrucks
Runnable runnable2 = () -> System.out.println("Hello World!");

Unterstützung für funktionale Programmierung

Lambda-Ausdrücke sind eine Manifestation der funktionalen Programmierung. Sie ermöglichen es, Funktionen als Argumente an Methoden zu übergeben oder als Rückgabewerte zurückzugeben. Diese Unterstützung macht Java flexibler in der funktionalen Programmierung und ermöglicht eine bessere Bewältigung von Aufgaben wie Sammlungsoperationen und parallelem Rechnen.

Beispiel

// Übergeben eines Lambda-Ausdrucks als Argument an eine Methode
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));

Variablenerfassung

Lambda-Ausdrücke können auf Variablen im äußeren Gültigkeitsbereich zugreifen. Diese Funktion wird als Variablenerfassung bezeichnet. Lambda-Ausdrücke können lokale Variablen implizit erfassen, die final oder effektiv final sind.

Beispiel

// Variablenerfassung
int x = 10;
MyFunction myFunction = y -> System.out.println(x + y);
myFunction.doSomething(5); // Ausgabe 15

Methodenreferenzen

Lambda-Ausdrücke können durch Methodenreferenzen weiter vereinfacht werden. Methodenreferenzen ermöglichen es, direkt auf Methoden vorhandener Klassen oder Objekte zu verweisen, ohne redundanten Code zu schreiben.

Beispiel

// Verwendung einer Methodenreferenz
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(System.out::println);

Parallelität

Lambda-Ausdrücke machen die Implementierung paralleler Operationen bequemer. Durch die Verwendung der Stream-API in Kombination mit Lambda-Ausdrücken kann paralleles Rechnen einfacher implementiert werden, was die Programmleistung verbessert.

Beispiel

// Verwendung von Lambda-Ausdrücken und Stream-API für paralleles Rechnen
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream().mapToInt(Integer::intValue).sum();

Die Einführung von Lambda-Ausdrücken macht die Java-Programmierung flexibler und prägnanter und fördert die Entwicklung der funktionalen Programmierung.


Beispiele für Lambda-Ausdrücke

Einfache Beispiele für Lambda-Ausdrücke:

// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

Geben Sie den folgenden Code in die Datei Java8Tester.java ein:

Java8Tester.java-Datei

public class Java8Tester { public static void main(String args[]){ Java8Tester tester = new Java8Tester(); //Typdeklaration MathOperation addition = (int a, int b) -> a + b; //Keine Typdeklaration MathOperation subtraction = (a, b) -> a - b; //Return-Anweisung in geschweiften Klammern MathOperation multiplication = (int a, int b) -> { return a * b; }; //Keine geschweiften Klammern und keine return-Anweisung MathOperation division = (int a, int b) -> a / b; System.out.println("10 + 5 = " + tester.operate(10, 5, addition)); System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction)); System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication)); System.out.println("10 / 5 = " + tester.operate(10, 5, division)); //Keine Klammern GreetingService greetService1 = message -> System.out.println("Hallo " + message); //Mit Klammern GreetingService greetService2 = (message) -> System.out.println("Hallo " + message); greetService1.sayMessage("Example"); greetService2.sayMessage("Google"); } interface MathOperation { int operation(int a, int b); } interface GreetingService { void sayMessage(String message); } private int operate(int a, int b, MathOperation mathOperation){ return mathOperation.operation(a, b); } }

Führen Sie das obige Skript aus, und die Ausgabe ist:

$ javac Java8Tester.java 
$ java Java8Tester
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Example
Hello Google

Bei der Verwendung von Lambda-Ausdrücken sind die folgenden zwei Punkte zu beachten:

  • Lambda-Ausdrücke werden hauptsächlich verwendet, um Methoden-Schnittstellen für die Inline-Ausführung zu definieren (zum Beispiel eine einfache Methodenschnittstelle). Im obigen Beispiel haben wir verschiedene Arten von Lambda-Ausdrücken verwendet, um die Methoden der MathOperation-Schnittstelle zu definieren, und dann haben wir die Ausführung von operation definiert.

  • Lambda-Ausdrücke ersparen die Umständlichkeit der Verwendung anonymer Methoden und verleihen Java einfache, aber leistungsstarke funktionale Programmierfähigkeiten.


Gültigkeitsbereich von Variablen

Lambda-Ausdrücke können nur auf äußere lokale Variablen verweisen, die als final gekennzeichnet sind. Das bedeutet, lokale Variablen, die außerhalb des Gültigkeitsbereichs des Lambda definiert sind, können innerhalb des Lambda nicht geändert werden; andernfalls tritt ein Kompilierungsfehler auf.

Geben Sie den folgenden Code in die Datei Java8Tester.java ein:

Java8Tester.java-Datei

public class Java8Tester { final static String salutation = "Hallo! "; public static void main(String args[]){ GreetingService greetService1 = message -> System.out.println(salutation + message); greetService1.sayMessage("Example"); } interface GreetingService { void sayMessage(String message); } }

Führen Sie das obige Skript aus, und die Ausgabe ist:

$ javac Java8Tester.java 
$ java Java8Tester
Hello! Example

Wir können auch direkt auf äußere lokale Variablen im Lambda-Ausdruck zugreifen:

Java8Tester.java-Datei

public class Java8Tester { public static void main(String args[]) { final int num = 1; Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); s.convert(2); //Die Ausgabe ist 3 } public interface Converter<T1, T2> { void convert(int i); } }

Lokale Variablen in Lambda-Ausdrücken müssen nicht als final deklariert werden, dürfen aber nicht durch nachfolgenden Code geändert werden (das heißt, sie haben implizit final-Semantik).

int num = 1;  
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5;  
//报错信息:Local variable num defined in an enclosing scope must be final or effectively 
 final

Es ist nicht erlaubt, einen Parameter oder eine lokale Variable mit demselben Namen wie eine lokale Variable innerhalb eines Lambda-Ausdrucks zu deklarieren.

String first = "";  
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());  //编译会出错 

Java 8 新特性Neue Funktionen in Java 8

Andere Erweiterungen