English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Java-Grundlagen-Tutorial

Java Flusskontrolle

Java Array

Java objektorientiert(I)

Java objektorientiert(II)

Java objektorientiert(III)

Java-Exception-Verarbeitung

Java Liste(List)

Java Queue(Stapel)

Java Map-Kollektion

Java Set-Kollektion

Java Eingabe-Ausgabe(I/O)

Java Reader/Writer

Andere Themen in Java

Java Lambda-Ausdrücke

In diesem Artikel werden wir durch Beispiele die Java-Lambda-Ausdrücke und deren Verwendung mit Funktionsinterface, generischen Funktionsinterface und Stream-API kennenlernen.

Lambda-Ausdrücke sind in Java 8erstmals eingeführt. Sein Hauptzweck ist es, die Ausdrucksfähigkeit der Sprache zu verbessern.

Aber bevor wir Lambda lernen, müssen wir zunächst das Funktionsinterface verstehen.

Was ist ein Funktionsinterface?

Wenn ein Java-Interface nur eine abstrakte Methode enthält, wird es als Funktionsinterface bezeichnet. Nur diese eine Methode spezifiziert die erwartete Verwendung des Interfaces.

Zum Beispiel ist das Interface Runnable in java.lang ein Funktionsinterface, da es nur eine Methode enthält, nämlich run().

Beispiel1:In Java Funktionsinterface definieren

import java.lang.FunctionalInterface;
@FunctionalInterface
public interface MyInterface{
    //Einzelner abstrakter Methode
    double getValue();
}

Im obigen Beispiel hat das Interface MyInterface nur eine abstrakte Methode getValue(). Daher ist es ein Funktionsinterface.

Hier verwenden wir den Annotation @FunctionalInterface. Diese Annotation zwingt den Java-Compiler, anzuzeigen, dass dieses Interface ein Funktionsinterface ist. Daher ist es nicht erlaubt, mehrere abstrakte Methoden zu haben. Es ist jedoch nicht obligatorisch.

In Java 7Wird in Java alsEinzelner abstrakter Methode (SAM)Typen. In Java 7In der Regel werden SAM-Typen in Java durch anonyme Klassen implementiert.

Beispiel2:Mit anonymen Klassen in Java SAM implementieren

public class FunctionInterfaceTest {
    public static void main(String[] args) {
        //Anonyme Klasse
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Ich habe gerade die Funktionsinterface Runnable implementiert.");
            }
        }).start();
    }
}

Ausgabe

Ich habe gerade die Funktionsinterface Runnable implementiert.

Hier können wir anonyme Klassen an Methoden übergeben. Dies hilft uns, in Java 7Programme mit weniger Code zu schreiben. Der Syntax ist jedoch immer noch schwierig und erfordert viele zusätzliche Zeilen.

Java 8Erweitert die Funktionalität von SAM. Da wir wissen, dass Funktionsinterfaces nur eine Methode haben, müssen wir den Namen dieser Methode nicht definieren, wenn wir sie als Parameter übergeben. Lambda-Ausdrücke ermöglichen dies.

Einführung in Lambda-Ausdrücke

Lambda-Ausdrücke sind im Wesentlichen anonyme oder namenlose Methoden. Lambda-Ausdrücke können nicht unabhängig ausgeführt werden. Stattdessen werden sie verwendet, um Methoden von Funktionsinterfaces zu implementieren.

Wie definiert man Lambda-Ausdrücke in Java?

So definieren wir Lambda-Ausdrücke in Java.

(Parameterliste) -> Lambda-Body

verwendeten neuen Operator (->)genannt Pfeil-Operator oder Lambda-Operator. Lassen Sie uns einige Beispiele erkunden,

Angenommen, wir haben eine solche Methode:

double getPiValue() {
    return 3.1415;
}

Wir können diesen Methoden mit Lambda-Ausdrücken wie folgt schreiben: }}

() -> 3.1415

In diesem Fall hat die Methode keine Parameter. Daher ist die linke Seite des Operators ein leerer Parameter. Rechts ist der Lambda-Körper, der die Operation des Lambda-Ausdrucks spezifiziert. In diesem Fall gibt er den Wert zurück3.1415。

Typen von Lambda-Körpern

In Java gibt es zwei Arten von Lambda-Körpern.

1. Einziger Ausdruckskörper

() -> System.out.println("Lambdas sind großartig");

Dieser Typ von Lambda-Körper wird Ausdruckskörper genannt.

2. Hauptkörper, der aus Codeblöcken besteht.

() -> {
    double pi = 3.1415;
    return pi;
};

Dieser Typ von Lambda-Körper wird Blockkörper genannt. Blockkörper erlauben es, dass der Lambda-Körper mehrere Anweisungen enthält. Diese Anweisungen sind in Klammern enthalten und Sie müssen nach den Klammern ein Semikolon hinzufügen.

Beachten Sie:Für Blockkörper sollten Sie immer ein return-Statement haben. Ein einzelner Ausdruckskörper jedoch benötigt kein return-Statement.

Beispiel3:Lambda-Ausdruck

Lassen Sie uns ein Java-Programm schreiben, das Lambda-Ausdrücke verwendet, um den Wert von Pi zurückzugeben.

Wie bereits erwähnt, werden Lambda-Ausdrücke nicht单独 ausgeführt. Stattdessen bilden sie die Implementierung der abstrakten Methoden, die durch das Funktionsinterface definiert sind.

Daher müssen wir zunächst ein Funktionsinterface definieren.

import java.lang.FunctionalInterface;
//Das ist ein Funktionsinterface
@FunctionalInterface
interface MyInterface{
    // 抽象方法
    double getPiValue();
}
public class Main {
    public static void main(String[] args) {
    //声明对MyInterface的引用
    MyInterface ref;
    
    // Lambda-Ausdruck
    ref = () -> 3.1415;
    
    System.out.println("Pi = "); + ref.getPiValue());
    } 
}

Ausgabe

Pi = 3.1415

In diesem Beispiel,

  • Wir haben eine Funktionsinterface namens MyInterface erstellt. Es enthält eine abstrakte Methode namens getPiValue().

  • Innerhalb der Main-Klasse erklären wir eine Referenz zu MyInterface. Beachten Sie, dass wir Referenzen zu Interfaces erklären können, aber nicht instantiieren können. Das liegt daran,
     

    //Es wird einen Fehler auslösen
    MyInterface ref = new myInterface();
    // Das ist gültig
    MyInterface ref;
  • Dann haben wir der Referenz einen Lambda-Ausdruck zugewiesen.

    ref = () -> 3.1415;
  • Schließlich rufen wir die Methode getPiValue() über das reference-Interface auf.

    System.out.println("Pi = "); + ref.getPiValue());

Lambda-Ausdrücke mit Parameter

Bis jetzt haben wir Lambda-Ausdrücke ohne Parameter erstellt. Aber ähnlich wie Methoden können Lambda-Ausdrücke auch Parameter haben. Zum Beispiel,

(n) -> (n%2)=0

在此,括号内的变量n是传递给lambda表达式的参数。Lambda主体接受参数并检查其是偶数还是奇数。

Beispiel4:将lambda表达式与参数一起使用

@FunctionalInterface
interface MyInterface {
    //抽象方法
    String reverse(String n);
}
public class Main {
    public static void main(String[] args) {
                //声明对MyInterface的引用
                //将lambda表达式分配给引用
        MyInterface ref = (str) -> {
            String result = "";
            for (int i = str.length();-1; i >= 0; i--){
                result += str.charAt(i);
            }
            
            return result;
        };
        //调用接口的方法
        System.out.println("Lambda reversed = " + ref.reverse("Lambda"));
    }
}

Ausgabe

Lambda reversed = adbmaL

泛型功能接口

到目前为止,我们已经使用了仅接受一种类型的值的功能接口。例如,

@FunctionalInterface
interface MyInterface {
    String reverseString(String n);
}

上面的功能接口仅接受String并返回String。但是,我们可以使功能接口通用,以便接受任何数据类型。如果不熟悉泛型,请访问Java泛型

Beispiel5:泛型功能接口和Lambda表达式

// GenericInterface.java
@FunctionalInterface
interface GenericInterface<T> {
    // 泛型方法
    T func(T t);
}
// GenericLambda.java
public class Main {
    public static void main(String[] args) {
                //声明对GenericInterface的引用
                // GenericInterface对String数据进行操作
                //为其分配一个lambda表达式
        GenericInterface<String> reverse = (str) -> {
            String result = "";
            for (int i = str.length();-1; i >= 0; i--)
            result += str.charAt(i);
            return result;
        };
        System.out.println("Lambda reversed = " + reverse.func("Lambda"));
                //声明对GenericInterface的另一个引用
                // GenericInterface对整数数据进行操作
                //为其分配一个lambda表达式
        GenericInterface<Integer> factorial = (n) -> {
            int result = 1;
            for (int i = 1; i <= n; i++)
            result = i * result;
            return result;
        };
        System.out.println("5Fakultät = " + factorial.func(5));
    }
}

Ausgabe

Lambda reversed = adbmaL
5Fakultät = 120

Im obigen Beispiel haben wir eine genische Funktionsinterface namens GenericInterface erstellt. Es enthält eine genische Methode func().

Innerhalb der Klasse:

  • GenericInterface<String> reverse - Erstellen Sie eine Referenz auf dieses Interface. Jetzt kann das Interface Daten des Typs String verarbeiten.

  • GenericInterface<Integer> factorial -Erstellen Sie eine Referenz auf dieses Interface. In diesem Fall wird das Interface für Daten des Typs Integer verwendet.

Lambda-Ausdrücke und Stream API

neujava.util.streamPaket wurde dem JDK hinzugefügt8daher ermöglicht es es Java-Entwicklern, Suchen, Filterungen, Mapping, Reduzieren usw. durchzuführen oder Operationen auf Listen und anderen Sammlungen durchzuführen.

Zum Beispiel haben wir einen Datenstrom (in unserem Beispiel eine Liste von Strings), bei dem jeder String der Name eines Landes und/Kombinationen von Regionen. Jetzt können wir diesen Datenstrom verarbeiten und nur Positionen aus Nepal abrufen.

Dafür können wir Stream API und Lambda-Ausdrücke kombinieren, um Massenoperationen im Stream auszuführen.

Beispiel6:Demonstration der Verwendung von Lambda und Stream API

import java.util.ArrayList;
import java.util.List;
public class StreamMain {
    //Verwenden Sie ArrayList, um ein Listenobjekt zu erstellen
    static List<String> places = new ArrayList<>();
    //Vorbereitung unserer Daten
    public static List getPlaces(){
        //Orte und Länder zur Liste hinzufügen
        places.add("Nepal, Kathmandu");
        places.add("Nepal, Pokhara");
        places.add("India, Delhi");
        places.add("USA, New York");
        places.add("Africa, Nigeria");
        return places;
    }
    public static void main(String[] args) {
        List<String> myPlaces = getPlaces();
        System.out.println("Orte aus Nepal:");
        
        myPlaces.stream()
                .filter((p) -> p.startsWith("Nepal"))
                .map((p) -> p.toUpperCase())
                .sorted()
                .forEach((p) -> System.out.println(p));
    }
}

Ausgabe

Orte aus Nepal:
NEPAL, KATHMANDU
NEPAL, POKHARA

Bitte beachten Sie die folgenden Anweisungen im obigen Beispiel:

myPlaces.stream()
        .filter((p) -> p.startsWith("Nepal"))
        .map((p) -> p.toUpperCase())
        .sorted()
        .forEach((p) -> System.out.println(p));

Hier verwenden wir Methoden wie filter(), map() und forEach() aus dem Stream API. Diese Methoden können Lambda-Ausdrücke als Eingabe akzeptieren.

Wir können auch unsere eigenen Ausdrücke basierend auf den gelernten Grammatiken definieren. Wie im obigen Beispiel gezeigt, ermöglicht dies eine erhebliche Reduzierung der Zeilenanzahl des Codes.