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.
Lambda-Ausdrücke verwenden einen Mechanismus, der als lokale Klassen und anonyme Klassen bezeichnet wird.
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.
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.
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.
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 \
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 \
Predicate<String> checker = (s)-> { return s.equals("Java"); };
boolean result = checker.test("Java");
System.out.println(result); //true
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.
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.
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