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

Detaillierte Erläuterung des virtuellen DOM in der Vue-Quellcodeanalyse

Warum brauchen wir virtuellen Dom? Virtual DOM wu...

IE8 verwendet den Multikompatibilitätsmodus, um Webseiten normal anzuzeigen

IE8 wird mehrere Kompatibilitätsmodi haben. Der IE...

Unglaubliche CSS-Navigationsleiste unterstreiche folgenden Effekt

Der erste Cutter in China github.com/chokcoco Hie...

So scrollen Sie manuell durch Protokolle im Linux-System

Die Protokollrotation ist eine sehr gängige Funkt...

So teilen Sie Daten in MySQL-Tabellen und -Datenbanken auf

Inhaltsverzeichnis 1. Vertikales (längsseitiges) ...

React implementiert Paging-Effekt

In diesem Artikel wird der spezifische Code für R...

Lösung für das Routing-Hervorhebungsproblem von Vue-Komponenten

Vorwort Früher habe ich den Cache verwendet, um d...

Details zum Vue Page Stack Manager

Inhaltsverzeichnis 2. Bewährte Methoden 2.1 Am Le...

Zusammenfassung der CSS-Schwebeelementanalyse

Float: links/rechts/keine; 1. Gleichstufiges Schw...

vue.config.js Verpackungsoptimierungskonfiguration

Die Informationen auf Baidu sind so vielfältig, d...

Erläuterung des Arbeitsmechanismus von Namenode und SecondaryNameNode in Hadoop

1) Prozess 2) FSImage und Bearbeitungen Nodenode ...

Verwandte Befehle zur vollständigen Deinstallation von Nginx unter Ubuntu 16.04

nginx Übersicht nginx ist ein kostenloser, quello...