Prinzipien und Beispiele für Lambda-Ausdrücke

Prinzipien und Beispiele für Lambda-Ausdrücke

Lambda-Ausdrücke

Lambda-Ausdrücke, auch Closures genannt, sind die wichtigste neue Funktion, die zur Veröffentlichung von Java 8 geführt hat.
Lambda ermöglicht die Verwendung einer Funktion als Methodenparameter (eine Funktion wird als Parameter an eine Methode übergeben).
Die Verwendung von Lambda-Ausdrücken kann den Code prägnanter und kompakter machen.

1. Bedarfsanalyse

Erstellen Sie einen neuen Thread und geben Sie die Aufgabe an, die der Thread ausführen soll

    öffentliche statische void main(String[] args) {
        // Einen neuen Thread starten neuer Thread(neuer Runnable() {
            @Überschreiben
            öffentliche Leere ausführen() {
                System.out.println("Im neuen Thread ausgeführter Code: "+Thread.currentThread().getName());
            }
        }).Start();
        System.out.println("Code im Hauptthread: " + Thread.currentThread().getName());
    }

Code-Analyse:

  1. Die Thread-Klasse erfordert eine Runnable-Schnittstelle als Parameter, in der die abstrakte Methode „run“ die Kernmethode ist, die zum Angeben des Thread-Task-Inhalts verwendet wird.
  2. Um den Hauptteil der Run-Methode anzugeben, müssen Sie die Implementierungsklasse Runnable verwenden.
  3. Um die Definition einer Runnable-Implementierungsklasse zu speichern, müssen Sie eine anonyme innere Klasse verwenden
  4. Die abstrakte Run-Methode muss überschrieben und neu geschrieben werden. Alle Methodennamen, Methodenparameter und Methodenrückgabewerte müssen fehlerfrei neu geschrieben werden.
  5. Tatsächlich interessieren wir uns nur für den Code im Methodenkörper

2. Lambda-Ausdrücke für Anfänger

Lambda-Ausdruck ist eine anonyme Funktion, die als Codestück verstanden werden kann, das übergeben werden kann

neuer Thread(() -> { System.out.println("Neuer Thread-Lambda-Ausdruck..." +Thread.currentThread().getName()); })
.Start();
Vorteile von Lambda-Ausdrücken: Vereinfacht die Verwendung anonymer innerer Klassen und hat eine einfachere Syntax.

Die Syntax anonymer innerer Klassen ist redundant. Nachdem ich Lambda-Ausdrücke ausprobiert hatte, fand ich heraus, dass Lambda-Ausdrücke eine Möglichkeit sind, anonyme innere Klassen zu vereinfachen.

3. Lambda-Syntaxregeln

Lambda eliminiert die objektorientierten Regeln und Vorschriften. Das Standardformat von Lambda besteht aus drei Teilen:

(Parametertyp Parametername) -> {
Code-Text;
}

Formatbeschreibung:

  • (Parametertyp Parametername): Parameterliste
  • {code body;} : Methodenkörper
  • ->: Pfeil, der Parameterliste und Methodenkörper trennt

3.1 Lambda Übung 1

Üben Sie Lambda ohne Parameter und ohne Rückgabewert

Definieren einer Schnittstelle

öffentliche Schnittstelle UserService {
    ungültig zeigen();
}

Erstellen Sie dann die Hauptmethode mit

öffentliche Klasse Demo03Lambda {

    öffentliche statische void main(String[] args) {
        goShow(neuer Benutzerdienst() {
            @Überschreiben
            öffentliche Leere zeigen () {
                System.out.println("Ausgeführte Methode anzeigen...");
            }
        });
        System.out.println("----------");
        goShow(() -> { System.out.println("Lambda-Show-Methode ausgeführt..."); });
    }

    öffentliche statische Leere goShow (Benutzerdienst Benutzerdienst) {
        userService.show();
    }
}

Ausgabe:

Die Show-Methode wird ausgeführt...
----------
Die Lambda-Show-Methode wird ausgeführt …

3.2 Lambda-Übung 2

Vervollständigen Sie einen Lambda-Ausdrucksfall mit Parametern und Rückgabewert

Erstellen eines Personenobjekts

@Daten
@AllArgsKonstruktor
@NoArgsConstructor
öffentliche Klasse Person {

    privater String-Name;

    privates ganzzahliges Alter;

    private Ganzzahlhöhe;

}

Anschließend speichern wir mehrere Personenobjekte in der Listensammlung und sortieren diese Objekte anschließend nach Alter.

    öffentliche statische void main(String[] args) {
        Liste<Person> Liste = neue ArrayList<>();
        Liste.Hinzufügen(neue Person("Jay Chou",33,175));
        list.add(neue Person("Andy Lau",43,185));
        list.add(new Person("Personen hinzufügen",38,177));
        list.add(new Person("Person im Kontext",23,170));

        Sammlungen.sort(Liste, neuer Komparator<Person>() {
            @Überschreiben
            öffentliche int vergleichen(Person o1, Person o2) {
                gibt o1.getAge()-o2.getAge() zurück;
            }
        });
        für (Person Person : Liste) {
            System.out.println(person);
        }
    }

Wir haben festgestellt, dass der zweite Parameter der Sortiermethode eine anonyme innere Klasse der Comparator-Schnittstelle ist und die ausgeführte Methode Parameter und Rückgabewerte hat, sodass wir sie als Lambda-Ausdruck umschreiben können

    öffentliche statische void main(String[] args) {
        Liste<Person> Liste = neue ArrayList<>();
        Liste.Hinzufügen(neue Person("Jay Chou",33,175));
        list.add(neue Person("Andy Lau",43,185));
        list.add(new Person("Personen hinzufügen",38,177));
        list.add(new Person("Person im Kontext",23,170));

        /*Collections.sort(Liste, neuer Komparator<Person>() {
            @Überschreiben
            öffentliche int vergleichen(Person o1, Person o2) {
                gibt o1.getAge()-o2.getAge() zurück;
            }
        });
        für (Person Person : Liste) {
            System.out.println(person);
        }*/
        System.out.println("------");
        Sammlungen.sort(Liste,(Person o1,Person o2) -> {
            gibt o1.getAge() - o2.getAge() zurück;
        });
        für (Person Person : Liste) {
            System.out.println(person);
        }
    }

Ausgabe

Person (Name=Aaron Kwok, Alter=23, Größe=170)
Person (Name=Jay Chou, Alter=33, Größe=175)
Person (Name=周星驰, Alter=38, Größe=177)
Person (Name=Andy Lau, Alter=43, Größe=185)

4. @FunctionalInterface-Annotation

@FunctionalInterface ist eine neue funktionale Annotation, die in JDK8 hinzugefügt wurde und angibt, dass die durch diese Annotation geänderte Schnittstelle nur eine abstrakte Methode haben kann.

/**
 * @FunktionaleSchnittstelle
 * Dies ist eine funktionale Annotation. Die durch diese Annotation geänderte Schnittstelle kann nur eine abstrakte Methode deklarieren*/


@FunktionaleSchnittstelle
öffentliche Schnittstelle UserService {

    ungültig zeigen();

}

5. Das Prinzip des Lambda-Ausdrucks

Das Wesentliche einer anonymen inneren Klasse besteht darin, während der Kompilierung eine Klassendatei zu generieren. XXXXX$1.Klasse

öffentliche Klasse Demo01Lambda {

    öffentliche statische void main(String[] args) {
        // Einen neuen Thread starten neuer Thread(neuer Runnable() {
            @Überschreiben
            öffentliche Leere ausführen() {
                System.out.println("Im neuen Thread ausgeführter Code: "+Thread.currentThread().getName());
            }
        }).Start();
        System.out.println("Code im Hauptthread: " + Thread.currentThread().getName());
        System.out.println("---------------");
        /*neuer Thread(() -> { System.out.println("Neuer Thread-Lambda-Ausdruck..." +Thread.currentThread().getName()); })
                .Start();*/
    }
}

Sie können auch das Dekompilierungstool verwenden, um den generierten Code anzuzeigen XJad-Tool zum Anzeigen

statische Klasse Demo01Lambda$1
 implementiert Runnable
{

 öffentliche void run()
 {
  System.out.println((new StringBuilder()).append("Im neuen Thread ausgeführter Code: " ).append(Thread.currentThread().getName()).toString());
 }

 Demo01Lambda$1()
 {
 }
}

Was ist also das Prinzip des Lambda-Ausdrucks? Wir verwenden auch das Dekompilierungstool zur Überprüfung

Für Klassendateien mit Lambda-Ausdrücken verwenden wir XJad zur Fehlerprüfung. Derzeit können wir ein mit JDK geliefertes Tool verwenden: javap, um den Bytecode zu disassemblieren.

javap -c -p Dateiname.Klasse

  • -c: bedeutet, den Code zu disassemblieren
  • -p: Alle Klassen und Mitglieder anzeigen

Das Ergebnis der Demontage:

E:\Arbeitsbereich\OpenClassWorkSpace\JDK8Demo\Ziel\Klassen\com\bobo\jdk\lambda>javap -c -p Demo03Lambda.class
Kompiliert aus „Demo03Lambda.java“
öffentliche Klasse com.bobo.jdk.lambda.Demo03Lambda {
  öffentliche com.bobo.jdk.lambda.Demo03Lambda();
    Code:
       0: aload_0
       1: invokespecial #1 // Methode java/lang/Object."<init>":()V
       4: Rückkehr

  öffentliche statische void main(java.lang.String[]);
    Code:
       0: invokedynamic #2, 0 // InvokeDynamic #0:show:()Lcom/bobo/jdk/lambda/service/UserService;
       5: invokestatic #3 // Methode goShow:(Lcom/bobo/jdk/lambda/service/UserService;)V
       8: Rückkehr

  öffentliche statische Leere goShow(com.bobo.jdk.lambda.service.UserService);
    Code:
       0: aload_0
       1: invokeinterface #4, 1 // Schnittstellenmethode com/bobo/jdk/lambda/service/UserService.show:()V
       6: Rückkehr

  private statische Leere lambda$main$0();
    Code:
       0: getstatic #5 // Feld java/lang/System.out:Ljava/io/PrintStream;
       3: ldc #6 // String-Lambda-Show-Methode wird ausgeführt …
       5: invokevirtual #7 // Methode java/io/PrintStream.println:(Ljava/lang/String;)V
       8: Rückkehr
}

In diesem dekompilierten Quellcode sehen wir eine statische Methode lambda$main$0(). Was macht diese Methode? Lassen Sie es uns durch Debuggen überprüfen:

Der obige Effekt kann wie folgt verstanden werden:

öffentliche Klasse Demo03Lambda {

    öffentliche statische void main(String[] args) {
        ....
    }

    private statische Leere lambda$main$0();
        System.out.println("Lambda-Show-Methode ausgeführt …");
    }
}

Um dies intuitiver zu verstehen, können wir beim Ausführen -Djdk.internal.lambda.dumpProxyClasses hinzufügen. Durch Hinzufügen dieses Parameters wird der interne Klassencode in eine Datei ausgegeben

java -Djdk.internal.lambda.dumpProxyClasses Name des auszuführenden Pakets. Klassenname

Befehlsausführung

E:\Arbeitsbereich\OpenClassWorkSpace\JDK8Demo\Ziel\Klassen>java -Djdk.internal.lambda.dumpProxyClasses com.bobo.jdk.lambda.Demo03Lambda
Die Lambda-Show-Methode wird ausgeführt …


Dekompilierter Inhalt:

Sie können sehen, dass diese anonyme innere Klasse die UserService-Schnittstelle implementiert und die show()-Methode überschreibt. In der Show-Methode wird Demo03Lambda.lambda$main$0() aufgerufen, was bedeutet, dass der Inhalt in Lambda aufgerufen wird.

öffentliche Klasse Demo03Lambda {

    öffentliche statische void main(String[] args) {
        goShow(neuer Benutzerdienst() {
            @Überschreiben
            öffentliche Leere zeigen () {
                Demo03Lambda.lambda$main$0();
            }
        });
        System.out.println("----------");
       
    }

    öffentliche statische Leere goShow (Benutzerdienst Benutzerdienst) {
        userService.show();
    }

    private statische Leere lambda$main$0();
        System.out.println("Lambda-Show-Methode ausgeführt …");
    }
}

Zusammenfassung:

Eine anonyme innere Klasse generiert beim Kompilieren eine Klassendatei.

Lambda-Ausdrücke bilden eine Klasse, wenn das Programm ausgeführt wird.

  1. Der Klasse wird eine neue Methode hinzugefügt. Der Methodenkörper dieser Methode ist der Code im Lambda-Ausdruck.
  2. Es wird auch eine anonyme innere Klasse bilden, die Schnittstelle implementieren und die abstrakte Methode überschreiben
  3. Das Überschreiben einer Methode in einer Schnittstelle ruft die neu generierte Methode auf

6. Abkürzung des Lambda-Ausdrucks

Basierend auf der Standardschreibweise von Lambda-Ausdrücken lauten die Regeln für die Verwendung von Auslassungspunkten wie folgt:

  1. Parametertypen in Klammern können weggelassen werden
  2. Befindet sich in der Klammer nur ein Parameter, kann die Klammer weggelassen werden.
  3. Wenn sich innerhalb der Klammern nur eine Anweisung befindet, können die Klammern, das Return-Schlüsselwort und das Anweisungssemikolon weggelassen werden.
öffentliche Klasse Demo05Lambda {

    öffentliche statische void main(String[] args) {
        goStudent((Stringname,Integeralter)->{
            returniere Name+Alter+" 6666 ...";
        });
        // Kurzform goStudent((name,age)-> name+age+" 6666 ...");
        System.out.println("------");
        goOrder((Stringname)->{
            System.out.println("--->" + name);
            Rückgabe 666;
        });
        // Abgekürzte Notation goOrder(name -> {
            System.out.println("--->" + name);
            Rückgabe 666;
        });
        goOrder(Name -> 666);
    }

    öffentliche statische Leere goStudent (StudentService studentService) {
        studentService.show("Weiter",22);
    }

    öffentliche statische Leere goOrder (OrderService orderService) {
        orderService.show("Li Si");
    }
    
}

7. Voraussetzungen für die Verwendung von Lambda-Ausdrücken

Die Syntax von Lambda-Ausdrücken ist sehr präzise, ​​aber Lambda-Ausdrücke können nicht beiläufig verwendet werden. Bei ihrer Verwendung gibt es mehrere Bedingungen, die besondere Aufmerksamkeit erfordern.

  1. Der Methodenparameter oder der lokale Variablentyp muss eine Schnittstelle sein, um Lambda verwenden zu können
  2. Es gibt nur eine abstrakte Methode in der Schnittstelle (@FunctionalInterface)

8. Vergleich zwischen Lambda und anonymen inneren Klassen

Vergleich zwischen Lambda und anonymen inneren Klassen

1. Die erforderlichen Typen sind unterschiedlich

  • Der Typ der anonymen inneren Klasse kann Klasse, abstrakte Klasse oder Schnittstelle sein
  • Der vom Lambda-Ausdruck benötigte Typ muss eine Schnittstelle sein

2. Die Anzahl der abstrakten Methoden ist unterschiedlich

  • Die Anzahl der abstrakten Methoden in der Schnittstelle, die von der anonymen inneren Klasse benötigt werden, ist beliebig.
  • Lambda-Ausdrücke erfordern nur eine abstrakte Methode in der Schnittstelle

3. Die Umsetzungsprinzipien sind unterschiedlich

  • Eine anonyme innere Klasse bildet nach der Kompilierung eine Klasse
  • Lambda-Ausdrücke generieren Klassen dynamisch, wenn das Programm ausgeführt wird.

Dies ist das Ende dieses Artikels über die Prinzipien und Beispiele von Lambda-Ausdrücken. Weitere Informationen zu Lambda-Ausdrücken finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Eine kurze Diskussion über die Operationen im Zusammenhang mit Lambda-Ausdrücken in Java
  • Neue Funktionen in Java8: Zusammenfassung der Lambda-Ausdrücke
  • Bringen Sie Ihnen bei, Java-Lambda-Ausdrücke zu verstehen und sie in einer Minute zu verwenden
  • Einführung in Java-Lambda-Ausdrücke: Lesen Sie einfach diesen Artikel
  • Detaillierte Erklärung der funktionalen Programmierung in Java und der Lambda-Ausdrücke

<<:  Detaillierte Erläuterung der Installation und Konfiguration des Redis- und phpredis-Erweiterungsvorgangs im Ubuntu 18.04-System

>>:  Tutorial zur Optimierung der Installationskonfiguration von MySQL 8.0.18

Artikel empfehlen

js fügt dynamisch Beispielcode für eine Liste eingekreister Zahlen hinzu

1. Fügen Sie zuerst das ul-Tag im Textkörper hinz...

Faint: „Nutzen Sie Web 2.0, um standardkonforme Seiten zu erstellen“

Heute sprach jemand mit mir über ein Website-Entw...

Drei Diskussionen zum Iframe Adaptive Height Code

Beim Erstellen einer B/S-Systemschnittstelle stößt...

Oberflächliches Webdesign

<br />Ich war schon immer der Meinung, dass ...

Der vollständige Leitfaden zum Rasterlayout in CSS

Grid ist ein zweidimensionales Rasterlayoutsystem...

Verwendung des Linux-Befehls ln

1. Befehlseinführung Mit dem Befehl ln werden Lin...

Details zu 7 Arten der Komponentenkommunikation in Vue3

Inhaltsverzeichnis 1. Kommunikationsmethode für V...

Verschiedene Methoden zum Neustarten von Mysql unter CentOS (empfohlen)

1. MySQL über RPM-Paket installiert Dienst MySQL ...

Tiefgreifendes Verständnis des Vue-Übergangs und der Animation

1. Wenn Sie DOM-Elemente einfügen, aktualisieren ...

CSS-Benennung: BEM, Scoped CSS, CSS-Module und CSS-in-JS erklärt

Der Anwendungsbereich von CSS ist global. Wenn da...