Ich habe versucht, Java-Lambda-Ausdrücke zusammenzufassen

Was ist ein Lambda-Ausdruck?

Neue Grammatik in Java 8 eingeführt. Vereinfachen Sie die Verarbeitungsbeschreibung, indem Sie den mit der lokalen Klasse und der anonymen Klasse beschriebenen Inhalt weglassen. Als typische Beispiele haben die Methoden von Collections.sort und Stream API profitiert.

Zerlegung der Lambda-Gleichung

Lambda-Ausdrücke verwenden einen Mechanismus, der als lokale Klassen und anonyme Klassen bezeichnet wird.

  1. Lokale Klasse

Eine lokale Klasse ist ein Mechanismus, der verwendet werden kann, indem eine Klasse während der Verarbeitung einer Methode deklariert wird.

public static void main(String[] args) {

  class Local {
    public void sayHello() {
      System.out.println("Hello!");
    }
  }

  Local local = new Local();
  local.sayHello(); // Hello!
}

Sie können auch eine lokale Klasse definieren, die die Schnittstelle implementiert.

public static void main(String[] args) {

  class Local implements Runnable {
    @Override
    public void run() {
      System.out.println("Hello Lambda!");
    }
  }

  Runnable runner = new Local();
  runner.run(); // Hello Lambda!
}

Schauen wir uns als nächstes die anonyme Klasse an.

  1. Anonyme Klasse

Anonyme Klasse ist ein Mechanismus, bei dem die Deklaration der lokalen Klasse, die die Schnittstelle implementiert, weggelassen wird. Hier ist ein Beispiel für eine anonyme Klasse, die die Runnable-Schnittstelle implementiert.

public static void main(String[] args) {

  Runnable runner = new Runnable() {
    @Override
    public void run() {
      System.out.println("Hello Lambda!");
    }
  };

  runner.run(); //Hello Lambda!
}

Es sieht so aus, als würden Sie eine Instanz der Rannable-Schnittstelle erstellen, aber Sie erstellen tatsächlich eine Instanz einer anonymen Klasse, die die Rannable-Schnittstelle implementiert. Schauen wir uns zum Schluss den Lambda-Ausdruck an.

  1. Lambda-Typ

In der anonymen Klasse werden "new Runnable () {}" und "public void run" weggelassen, um einen Lambda-Ausdruck zu erstellen.

public static void main(String[] args) {

  Runnable runner = () -> { System.out.println("Hello Lambda!"); };
  runner.run(); //Hello Lambda!
}

Das erste () stellt das Argument der Ausführungsmethode dar, und der Inhalt von-> {} ist der Implementierungsinhalt der Ausführungsmethode. Der Runner-Variablen wird eine Instanz einer anonymen Klasse zugewiesen, die Runnable implementiert. Mit anderen Worten, ein Lambda-Ausdruck ist ein Ausdruck, der eine Instanz erstellt, die eine Schnittstelle implementiert.

Wenn ich "new Runnable () {}" weglasse, weiß ich übrigens nicht, welche Art von Instanz ich erstellen soll. Java verfügt über einen Mechanismus, mit dem automatisch auf den Typ der zuzuweisenden Variablen geschlossen werden kann. Dieser Mechanismus wird als Typinferenz bezeichnet.

Wenn Sie "public void run" weglassen, wissen Sie auch nicht, welche Methode für eine Schnittstelle mit mehreren definierten Methoden überschrieben werden soll. Daher können Lambda-Ausdrücke nur Schnittstellen mit einer abstrakten Methode verwenden.

Die Rannable-Schnittstelle allein kann nur Lambda-Ausdrücke ohne Argumente und ohne Rückgabewert erstellen. Wenn Sie es in einer anderen Form erstellen möchten, wurde eine funktionale Schnittstelle hinzugefügt. Verwenden Sie diese.

Funktionsschnittstelle

Eine funktionale Schnittstelle ist eine Schnittstelle, die Lambda-Ausdrücken und Methodenreferenzen zugewiesen werden kann.

Der Zustand einer funktionalen Schnittstelle ist grob gesagt eine Schnittstelle, für die nur eine abstrakte Methode definiert ist. Statische Methoden und Standardmethoden können enthalten sein (als Bedingung der Funktionsschnittstelle ignoriert). Wenn eine öffentliche Methode in der Object-Klasse als abstrakte Methode in der Schnittstelle definiert ist, wird diese Methode ebenfalls ignoriert. (Eine Schnittstelle, die diese Bedingung erfüllt, wird in JDK1.8 jetzt als "funktionale Schnittstelle" bezeichnet.)

Unter dem Paket java.util.function von SE8 wurden viele neue Schnittstellen hinzugefügt. https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/package-summary.html

Dieses Mal werde ich die am häufigsten verwendeten Schnittstellen vorstellen.

2-1. Function<T, R> Function ist eine funktionale Schnittstelle zum Konvertieren von Werten. In Funktion \ <T, R> gibt T den Typ des Arguments der Methode an, und R gibt den Typ des Rückgabewerts an. Nimmt ein Argument, konvertiert (berechnet) es und gibt einen anderen Wert zurück. Die Methode ist R Apply (T).

Function<Integer, String> asterisker = (i) -> { return "*"+ i; };
String result = asterisker.apply(10);
System.out.println(result); // *10

2-2. Consumer<T> Consumer ist eine funktionale Schnittstelle, um Argumente zu empfangen und für die Verarbeitung zu verwenden. T in Consumer \ gibt den Typ des Methodenarguments an. Da es keinen Wert zurückgibt, wird es grundsätzlich verwendet, um Nebenwirkungen zu verursachen. Die Methode ist void accept (T).

Consumer<String> buyer = (goods) -> { System.out.println(goods + "ich kaufte"); };
buyer.accept("Reisbällchen"); // Reisbällchenを購入しました。

2-3. Predicate<T> Prädikat ist eine funktionale Schnittstelle für Urteile. T in Prädikat \ gibt den Typ des Methodenarguments an. Erhält ein Argument, urteilt und gibt einen booleschen Wert zurück (Beurteilungsergebnis). Die Methode ist der Boolesche Test (T).

Predicate<String> checker = (s)-> { return s.equals("Java"); };
boolean result = checker.test("Java");
System.out.println(result); //true

Absicht, Lambda-Ausdruck zu verwenden

Der folgende Code beschreibt die Stream-API mithilfe von Lambda-Ausdrücken.

List<Integer> numbers = List.of(3, 1, -4, 1, -5, 9, -2, 6, 5, 3, 5);
numbers.stream()
        .filter(number -> Math.abs(number) >= 5)
        .forEach(System.out::println);

Das Ausgabeergebnis ist wie folgt.

-5
9
6
5
5

Schauen wir uns als nächstes den Code an, der ohne Verwendung des Lambda-Ausdrucks geschrieben wurde.

List<Integer> numbers = List.of(3, 1, -4, 1, -5, 9, -2, 6, 5, 3, 5);

numbers.stream()
        .filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer number) {
                return Math.abs(number) >= 5;
            }
        })
        .forEach(new Consumer<Integer>() {
            @Override
            public void accept(Integer number) {
                System.out.println(number);
            }
        });

Wie in der Lambda-Ausdruckszerlegung eingeführt, nimmt die Anzahl der Methodenbeschreibungen zum Erstellen und Ausführen von Schnittstellen zu. Die Menge des geschriebenen Codes hat zugenommen und die Aussichten für die Verarbeitung sind sehr schlecht geworden. Auf diese Weise wird die Verarbeitungsbeschreibung präzise und leicht verständlich gemacht.

Lambda-Grammatik

Erklärt die Grammatik des Lambda-Ausdrucks. Das Folgende ist die grundlegende Grammatik des Lambda-Ausdrucks.

(Streit) -> {wird bearbeitet; }

Das Folgende ist gemäß dieser Grammatik geschrieben.

// (1)Wenn es Argumente und Rückgabewerte gibt
(Integer number) -> {
    return Math.abs(number) >= 5;
}

// (2)Wenn es keinen Rückgabewert gibt
(Integer number) -> {
    System.out.println(number);
}

// (3)Wenn es keine Argumente oder Rückgabewerte gibt
() -> {
    System.out.println("Hello!");
}

(1) ist ein Beispiel für ein Argument und einen Rückgabewert wie Predicate. Die Verarbeitung wird unter Verwendung der durch das Argument angegebenen Nummer durchgeführt, und der Rückgabewert wird zurückgegeben. (2) ist ein Beispiel ohne Rückgabewert wie Consumer. In diesem Fall muss keine return-Anweisung geschrieben werden. Beschreiben Sie für die Verarbeitung ohne Argumente wie in (3) den Argumentteil in (). Zum Beispiel java.lang.Runnable.

In Lambda-Ausdrücken kann der Argumenttyp auch weggelassen werden. Und Sie können die Klammern () um das Argument nur weglassen, wenn Sie nur ein Argument haben. Es kann nicht weggelassen werden, wenn es kein Argument gibt oder wenn es zwei oder mehr gibt. Die Anwendung dieser Regel auf (1) und (3) ergibt:

// (1)Weil es nur ein Argument gibt( )Kann ausgelassen werden
number -> {
    return Math.abs(number) >= 5;
}

// (3)Weil es kein Argument gibt( )Kann nicht weggelassen werden
() -> {
    System.out.println("Hello!");
}

Wenn nur eine Zeile verarbeitet werden muss, können Sie außerdem die mittlere Klammer {}, return und das Semikolon am Ende des Satzes weglassen. Die Abkürzungen für (1) bis (3) sind wie folgt.

// (1)Wenn es Argumente und Rückgabewerte gibt
number -> Math.abs(number) >= 5

// (2)Wenn es keinen Rückgabewert gibt
number -> System.out.println(number)

// (3)Wenn es keine Argumente oder Rückgabewerte gibt
() -> System.out.println("Hello!")

Schließlich kann das Argument selbst unter Verwendung der Methodenreferenz nur dann weggelassen werden, wenn der Verarbeitungsinhalt ein Methodenaufruf ist und das Argument eindeutig bestimmt wird. Die Methodenreferenz hat die folgende Syntax.

Name der Klasse::Methodenname

Diese Methodenreferenz kann nur in (2) angewendet werden. Wenn (2) unter Verwendung der Methodenreferenz beschrieben wird, ist dies wie folgt.

System.out::println

Die System.out.println-Methode ist eine Methode, die nur ein Argument akzeptiert, und es ist klar, dass der Wert des Arguments Integer übergeben wird, sodass eine Methodenreferenz verfügbar ist. Andererseits kann in (1) die Methodenreferenz nicht verwendet werden, da nach dem Methodenaufruf eine Größenbeurteilung von> = 5 erfolgt. Da in (3) der Wert "Hallo!" Für das Argument angegeben ist, kann nicht gesagt werden, dass das Argument eindeutig bestimmt ist, und die Methodenreferenz kann auch hierfür nicht verwendet werden.

Schauen wir uns vor diesem Hintergrund die Stream-Verarbeitung früher an.

List<Integer> numbers = List.of(3, 1, -4, 1, -5, 9, -2, 6, 5, 3, 5);
numbers.stream()
        .filter(number -> Math.abs(number) >= 5)
        .forEach(System.out::println);

Sie können sehen, dass die in (1) und (2) gelernten Lambda-Ausdrücke in die streamAPI eingebettet sind.

Referenzartikel

Grundlegendes zu Java 8 Lambda-Ausdrücken Modernes Java mit Lambda-Ausdrücken und Stream-APIs gelernt - Die Gegenwart der Java-Sprache, die sich durch die Einbeziehung von Funktionstypen ändert

Recommended Posts

Ich habe versucht, Java-Lambda-Ausdrücke zusammenzufassen
Ich habe versucht, das Java-Lernen zusammenzufassen (1)
Ich habe jetzt versucht, Java 8 zusammenzufassen
[Java] Einführung in den Lambda-Ausdruck
[Einführung in Java] Über Lambda-Ausdrücke
Ich habe versucht, die Unterstützung für iOS 14 zusammenzufassen
Ich habe versucht, mit Java zu interagieren
Verwendung von Java-Lambda-Ausdrücken
Ich habe versucht, die Grundlagen von Kotlin und Java zusammenzufassen
Ich habe versucht, die verwendeten Methoden zusammenzufassen
Ich habe versucht, die Stream-API zusammenzufassen
Was ist Docker? Ich habe versucht zusammenzufassen
Ich habe versucht, die Methoden von Java String und StringBuilder zusammenzufassen
Verstehen Sie Java 8 Lambda-Ausdrücke
Über Java-Lambda-Ausdrücke
Erläutern Sie Java 8-Lambda-Ausdrücke
Ich habe versucht, über JVM / Garbage Collection zusammenzufassen
Ich habe versucht, eine Standardauthentifizierung mit Java durchzuführen
[Java] Zusammenfassung, wie Lambda-Ausdrücke weggelassen werden
Java Ich habe versucht, einen einfachen Block zu brechen
Ich habe versucht, neunundneunzig in Java auszugeben
Ich habe versucht, Alexa-Fähigkeiten mit Java zu erstellen
Ich habe versucht, den Block mit Java zu brechen (1)
[Einführung in Java] Ich habe versucht, das Wissen zusammenzufassen, das ich für wesentlich halte
Ich habe versucht, TCP / IP + BIO mit JAVA zu implementieren
Ich habe versucht, die Firebase-Push-Benachrichtigung in Java zu implementieren
[Java 11] Ich habe versucht, Java auszuführen, ohne mit Javac zu kompilieren
[Java Silver] Zusammenfassung der Punkte im Zusammenhang mit Lambda-Ausdrücken
[Java] Ich habe versucht, Paizas B-Rang-Problem zu lösen
Ich habe versucht, SQS mit AWS Java SDK zu betreiben
# 2 [Anmerkung] Ich habe versucht, neunundneunzig mit Java zu berechnen.
Ich habe den Eingabe- / Ausgabetyp von Java Lambda ~ Stream Version ~ ausprobiert
Ich habe versucht, eine Clova-Fähigkeit in Java zu erstellen
Ich habe Drools (Java, InputStream) ausprobiert.
Ich habe versucht, eine Anmeldefunktion mit Java zu erstellen
Ich habe versucht, verschiedene link_to zusammenzufassen, die dieses Mal verwendet wurden
Ich habe versucht, Sterling Sort mit Java Collector zu implementieren
Ich habe versucht, Java REPL zu verwenden
[Java] Ich habe versucht, die Yahoo API-Produktsuche zu implementieren
Ich habe versucht, yum-cron zu verifizieren
Ich habe versucht, die Methode der gegenseitigen Teilung von Eugrid in Java zu implementieren
~ Ich habe jetzt versucht, funktionale Programmierung mit Java zu lernen ~
Ich habe versucht, Metaprogrammierung mit Java
Ich habe versucht herauszufinden, was sich in Java 9 geändert hat
Ich habe versucht, mit Chocolatey eine Java8-Entwicklungsumgebung zu erstellen
Ich habe versucht, eine Java EE-Anwendung mit OpenShift zu modernisieren.
[JDBC] Ich habe versucht, von Java aus auf die SQLite3-Datenbank zuzugreifen.
Ich habe versucht, Java Optional und Guard-Klausel koexistieren zu lassen
Ich habe die grundlegende Grammatik von Ruby kurz zusammengefasst
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Entwicklungstools) zusammenzufassen.
Ich habe versucht, in Java von einer Zeichenfolge in einen LocalDate-Typ zu konvertieren
Ich habe versucht, persönlich nützliche Apps und Entwicklungstools (Apps) zusammenzufassen.
Ich habe versucht, Dapr in Java zu verwenden, um die Entwicklung von Mikroservices zu erleichtern
Ich habe einen RESAS-API-Client in Java erstellt
Ich habe versucht, die Objektorientierung auf meine Weise zusammenzufassen.
Java-Lambda-Ausdruck, der mit Comparator gelernt wurde
Ich habe versucht, C # (Indexer) zu kauen.
Ich habe versucht, UDP mit Java zu kommunizieren