Verwenden Sie zum Ausführen eines Threads in Java eine Unterklasse, die die Thread-Klasse erbt, und Es gibt eine Methode, die eine Unterklasse verwendet, die die Runnable-Schnittstelle implementiert. Diesmal wird letzteres als Beispiel für eine kurze Erklärung des Lambda-Ausdrucks genommen.
Function.java
public class Function implements Runnable{
@Override
public void run() {
//Was im Thread zu verarbeiten ist
System.out.println("hello!");
}
}
Main.java
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new Function());
thread.start();
System.out.println("finish!");
}
}
Ich denke, die Ausgabe wird so aussehen.
finish!
hello!
Welche Beziehung besteht zwischen der Thread-Klasse und der Runnable-Schnittstelle?
Das Strategiemusterdesign des GoF-Designmusters wird verwendet.
Grob gesagt soll das Strategiemuster "einen austauschbaren Algorithmus realisieren".
Die Klasse, die ursprünglich eine war, ist für den gesamten Verarbeitungsfluss verantwortlich.
Teilen wir es in Klassen ein, die für bestimmte Algorithmen zuständig sind.
Durch Verwendung des Strategiemusters mit dem Benutzer (Thread-Klasse)
Die zu verwendende Seite (die Klasse, die die Runnable-Schnittstelle realisiert)
Da es nicht direkt zusammenhängen muss, ist es möglich, einen Algorithmus zu realisieren, der später ersetzt werden kann.
(Für diejenigen, die mehr über Strategiemuster erfahren möchten, siehe hier)
Die Klasse, die die Schnittstelle realisiert hat, ist jedoch kompliziert (FunctionHard-Klasse im UML-Diagramm).
Es gibt so etwas wie eine Klasse, die einfachen Code erfordert (FunctionEasy-Klasse im UML-Diagramm).
Neue Klassen nacheinander, auch mit einfachem Code Ist es nicht ärgerlich definieren zu müssen? darüber.
Um das in der Einführung vorgestellte Problem zu lösen, verwenden wir den aus Java SE 8 eingeführten Lambda-Ausdruck. Der folgende Code wird durch einen Lambda-Ausdruck ersetzt, anstatt eine FunctionEasy-Klasse zu erstellen.
Lambda.java
public class Lambda {
public static void main(String[] args) {
Runnable r = () -> System.out.println("hello!");
Thread thread = new Thread(r);
thread.start();
System.out.println("finish!");
}
}
Sie brauchen nur eine Zeile wie diese. Erfrischend! Lambda-Ausdrücke sind "beim Instanziieren einer funktionalen Schnittstelle Sie können sich das als "eine Notation vorstellen, die kein kompliziertes Schreiben erfordert".
Eine Schnittstelle, die nur eine Methode hat, die implementiert werden muss, wird als "funktionale Schnittstelle" bezeichnet. Es wird auch als "SAM-Schnittstelle (Single Abstarct Method)" bezeichnet.
Wie Sie aus SAM sehen können, gibt es also nur eine abstrakte Methode Welche Methode implementiert der Lambda-Ausdruck? Was ist mit Argumenten und Rückgabewerten? Inferenz ist möglich. Es ist nicht erforderlich, den Methodennamen einzeln zu bestimmen. Polymorphismus kann realisiert werden, ohne eine Klasse vorzubereiten, die die Schnittstelle realisiert.
Vor Java8 wurde es von einer anonymen Klasse realisiert. Anonyme Klassen werden manchmal als anonyme Klassen bezeichnet.
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("hello!");
}
}
Es ist lang und unlesbar.
Lambda-Ausdrücke sind in Java 8 erschienen und es ist einfacher geworden, sie zu schreiben.
Runnable r = () -> {
System.out.println("hello!");
}
Die Lambda-Ausdrucksdeklaration besteht aus der Argumentvariablendeklaration und dem Verarbeitungsblock, wie unten gezeigt.
(Streit) -> {wird bearbeitet; };
"->" Wird als Pfeiloperator bezeichnet.
Einige Lambda-Ausdrücke können weggelassen werden. Folgen wir als Beispiel dem folgenden Prototyp.
Prototyp
Sample sample = (String a) -> { System.out.println(a);};
Wenn das Argument nur ** ist, wenn es eines gibt **, können die Klammern "()" weggelassen werden. Außerdem kann auf den Typ des Arguments geschlossen werden, sodass es weggelassen werden kann.
Abkürzungsnotation 1
Sample sample = a -> { System.out.println(a);};
Wenn der Methodenkörper aus einer Zeile besteht, können auch die mittlere Klammer "{}" und das Semikolon ";" am Ende des Satzes weggelassen werden. Im Fall einer return-Anweisung kann die Rückgabe ebenfalls weggelassen werden.
Abkürzungsnotation 2
Sample sample = a -> System.out.println(a);
Wenn das Argument abgeleitet werden kann, wird außerdem die Methode aufgerufen Klassenname :: Methodenname Objektname :: Methodenname Es kann so weggelassen werden.
Abkürzungsnotation 3
Sample sample = System.out::println;
** Eine Variable mit demselben Namen wie die in der Methode deklarierte lokale Variable kann nicht als Argumentname des Lambda-Ausdrucks verwendet werden. ** ** ** Das Folgende führt zu einem Kompilierungsfehler.
public class Sample {
public static void main(String[] args) {
String a = "sample";
Function f = a -> System.out.println(a); //Error
//Abkürzung
}
}
Da der Variablenname a bereits als lokale Variable deklariert wurde, kann er nicht als Argumentname für einen Lambda-Ausdruck verwendet werden.
** Um von innerhalb des Lambda-Ausdrucks auf eine außerhalb des Lambda-Ausdrucks deklarierte lokale Variable zugreifen zu können, muss die lokale Variable endgültig sein. Wenn der endgültige Modifikator nicht angehängt ist, muss er praktisch endgültig sein. ** ** **
Sie können über den Lambda-Ausdruck auf die lokalen Variablen der Methode zugreifen, die den Ausdruck umgibt. (Wenn Sie vor der Konvertierung in einen Lambda-Ausdruck darüber nachdenken, ist das so.) Sie können wie folgt auf die lokalen Variablen der Methode zugreifen, die den Ausdruck innerhalb des Lambda-Ausdrucks deklariert:
"Im Wesentlichen endgültig" bedeutet eine Variable, die sich nicht ändert, auch wenn sie nicht endgültig qualifiziert ist. Wenn Sie den Wert einer lokalen Variablen in einem Lambda-Ausdruck wie unten gezeigt ändern, tritt ein Kompilierungsfehler auf.
public class Sample {
public static void main(String[] args) {
String a = "sample";
Function f = () -> {
a = "change"; //Error
System.out.println(a);
};
//Abkürzung
}
}
Häufig verwendete Funktionsschnittstellen befinden sich im Paket java.util.function. Insbesondere sind die folgenden fünf Funktionsschnittstellen bekannt.
Funktionsschnittstelle | Methode | Streit | Rückgabewert | Erläuterung |
---|---|---|---|---|
Consumer<T> | void accept(T) | Ja | Keiner | "Verbraucher", der keinen Wert zurückgibt |
Supplier<T> | T get() | Keiner | Ja | "Lieferant" gibt einen Wert zurück |
Predicate<T> | boolean test(T) | Ja | Ja | "Bestätigung", die einen booleschen Wert zurückgibt |
Function<T, R> | R apply(T) | Ja | Ja | "Verarbeitung", die ein Argument empfängt und das Ergebnis des angegebenen Typs zurückgibt |
UnaryOperator<T> | T apply(T t) | Es gibt zwei | Ja | "Operation", die das Berechnungsergebnis zurückgibt |
Die Sammlungs-API verfügt über viele Standardmethoden zum Bearbeiten von Liste und Zuordnung.
Beispielsweise verfügt java.util.List über eine Methode namens * removeIf (Prädikatfilter) *, mit der Elemente entfernt werden, die dem Filter entsprechen. Wenn Sie den Lambda-Ausdruck verwenden, benötigen Sie nur eine Zeile.
RemoveIf.java
import java.util.ArrayList;
import java.util.Arrays;
public class RemoveIf {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>(Arrays.asList("aaaa", "bbb", "cc"));
list.removeIf(v -> v.length() > 3);
System.out.println(list); //Ergebnis: [bbb, cc]
}
}
Es gibt viele andere Methoden, mit denen Sie einen Lambda-Ausdruck angeben können. Lassen Sie uns selbst untersuchen und es mit einem Lambda-Ausdruck implementieren, um sich daran zu gewöhnen.
Es gibt viele WEB-Anwendungen, deren Serverseite unter Java 8 ausgeführt wird. Daher denke ich, dass die Lambda-Ausdrucks- und Stream-API unvermeidliches Wissen ist, wenn Sie jetzt Java ausführen. Dennoch scheint es einige Dinge zu geben, die im Java-Newcomer-Training nicht gelehrt werden. Ich habe versucht, es für Neulinge so einfach wie möglich zusammenzufassen. Es tut mir leid, wenn es einen Teil gibt, der schwer zu verstehen ist.
Nächstes Mal werde ich die Einführung in die Stream-API in der nächsten Woche zusammenfassen.
(Aktualisiert am 22. Dezember 2019) Fortsetzung etwas → [Java] Einführung in die Stream-API
Recommended Posts