Java 8 bietet erweiterte Funktionen für die funktionale Programmierung.
Fassen Sie zusammen, welche Funktionen funktionale Schnittstellen und Methodenreferenzen sind.
Goal Sie können diesen Quellcode lesen und verwenden.
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "", "charlie", "alpha");
strings.stream()
.filter(s -> !s.isEmpty())
.map(s -> s.substring(0, 1).toUpperCase() + s.substring(1))
.forEach(System.out::println);
// Bravo
// Charlie
// Alpha
}
Was ist eine funktionale Schnittstelle und wofür ist sie gedacht? Um es zu verstehen, ist es notwendig, das Konzept der ** Primärfunktion ** zu verstehen.
Erstklassige Funktionen (Englisch: erstklassige Funktion) [1] ist die Natur von Programmiersprachen, die Funktionen als erstklassige Objekte oder solche Funktionen behandeln können Das ist.
Erstklassiges Objekt?
Erstklassige Objekte sind unbegrenzte Grundoperationen in einer Programmiersprache, wie z. B. Erstellung, Zuweisung, Arithmetik und Übergabe (als Argumente / Rückgabewerte). Es ist ein Objekt, das verwendet werden kann.
Das war's
Java-Funktionen (Methoden) können nicht Variablen zugewiesen oder für Rückgabewerte / Argumente verwendet werden. Java ist eine Sprache, die die Eigenschaften erstklassiger Funktionen nicht erfüllt.
Erstklassige Funktionen sind für funktionale Sprachen unverzichtbar und werden täglich in Form von Funktionen höherer Ordnung verwendet.
** Das Verhalten kann durch Funktionen von außen manipuliert werden. ** **. z.B. Sortierregeln
List<String> strings = Arrays.asList("bravo", "charlie", "alpha");
Collections.sort(strings);
System.out.println(strings); // -> [alpha, bravo, charlie]
Collections.sort(strings, Comparator.reverseOrder());
System.out.println(strings); // -> [charlie, bravo, alpha]
Benri.
Ist es nicht der aktuelle Code Java?
Ein Entwurfsmuster, das konzipiert wurde, weil die Funktion nicht als primäres Objekt verfügbar ist.
Mit Java können Sie Strategiemuster mithilfe von Polymorphismus mit Klassenmethodenüberschreibungen implementieren.
Ich werde die Details weglassen, aber es sieht so aus.
public static <T> void sort(List<T> list, Comparator<? super T> c) {
if (c.compare(a, b) < 0) {
//a ist kleiner
}else {
//b ist kleiner
}
}
Die Sortierregel wird gemäß der Implementierungsklasse der als Argument empfangenen Comparator-Schnittstelle bestimmt. Die Praxis, dass die Methode selbst nicht über ein Argument übergeben wird, sondern die Verarbeitung der Methode von außen über die Schnittstelle übergeben werden kann.
Der eigentliche Sortiervorgang sieht so aus jdk/TimSort.java at master · openjdk/jdk
Dieses Entwurfsmuster muss in Sprachen, in denen die Funktion ein primäres Objekt ist, nicht besonders auffällig sein.
Dieses Muster wird implizit in Sprachen verwendet, in denen die Funktion ein primäres Objekt ist.
Java kann Funktionen (Methoden) wie erstklassige Objekte mithilfe von Schnittstellen verarbeiten.
Ab Java8 wird die Schnittstelle, mit der eine Funktion (Methode) als erstklassiges Objekt behandelt wird, wie der vorherige Komparator, als ** Funktionsschnittstelle ** bezeichnet. Da der Zweck darin besteht, Funktionen (Methoden) als erstklassige Objekte zu behandeln, gibt es nur eine abstrakte Methode für funktionale Schnittstellen.
Einige der in der Vergangenheit bereitgestellten Schnittstellen, wie z. B. Comparator und Runnable, haben gerade neue Namen erhalten. Die Funktion ist die gleiche wie bei einer normalen Schnittstelle. Die Anmerkung ** @ FunctionalInterface ** wurde der Funktionsschnittstelle hinzugefügt. e.g. java.lang.Runnable
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface {@code Runnable} is used
* to create a thread, starting the thread causes the object's
* {@code run} method to be called in that separately executing
* thread.
* <p>
* The general contract of the method {@code run} is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
jdk/FunctionalInterface.java at master · openjdk/jdk
@FunctionalInterface Anmerkungen für funktionale Schnittstellen hinzugefügt. Zur Laufzeit passiert nichts (die funktionale Schnittstelle ist funktional eine normale Schnittstelle, daher gibt es keine spezielle Verarbeitung). Beim Kompilieren wird geprüft, ob die Eigenschaften der Funktionsschnittstelle erfüllt sind.
Mit anderen Worten, es ist nicht unbedingt erforderlich, wenn die Funktionen der Funktionsschnittstelle verwendet werden. Da jedoch klar festgestellt werden kann, dass es sich eher um eine funktionale als um eine normale Schnittstelle handelt, sollte sie beim Erstellen einer funktionalen Schnittstelle hinzugefügt werden.
Bei der Behandlung einer Funktion (Methode) über eine Funktionsschnittstelle wird die zu behandelnde Methode vom Java-Typsystem beeinflusst. Insbesondere wenn im Folgenden verschiedene Methoden behandelt werden, müssen unterschiedliche Funktionsschnittstellen verwendet werden.
java8 bietet eine Standardfunktionsschnittstelle, die das Vorhandensein / Fehlen eines Rückgabewerts und den Typ eines Arguments abstrahiert und verfügbar macht. Grundsätzlich ist diese Schnittstelle ausreichend, und es wird gesagt, dass Sie die Verwendung dieser Schnittstelle in Betracht ziehen sollten. (Außer bei üblichen wie Runnable)
** Typische Standardfunktionsschnittstelle **
Name der Schnittstelle | Name der abstrakten Methode | Beispiel |
---|---|---|
Function<T,R> | R apply(T t) | Arrays::asList |
Predicate |
boolean test(T t) | Collections::isEmpty |
Consumer<T> | void accept(T t) | System.out::println |
Supplier<T> | T get() | Instant::now |
UnaryOperator<T> | T apply(T t) | String::toLowerCase |
BinaryOperator<T> | T apply(T t1, T t2) | BigInteger::add |
java.util.function (Java Platform SE 8 )
Erstellen wir einen Prozess zum Verarbeiten und Ausgeben einer Zeichenfolge. Beim Aufrufen des auszugebenden Prozesses wird die Zeichenfolge nach dem Bearbeitungsprozess ausgegeben, indem die Bearbeitungsprozessfunktion gemeinsam übergeben wird. Versuchen Sie, ein Programm zu erstellen, das nach der Konvertierung aller in Großbuchstaben ausgegeben wird.
Ausgabe nach Ausführung der übergebenen Funktion.
Die Funktionsschnittstelle nimmt eine Funktion an, die eine Zeichenfolge vor der Änderung (Zeichenfolge) empfängt und die Zeichenfolge nach der Änderung (Zeichenfolge) zurückgibt und "UnaryOperator
static void print(String word, UnaryOperator<String> operator) {
String newWord = operator.apply(word);
System.out.println(newWord);
}
Eine Funktion, die in Großbuchstaben konvertiert wird.
Implementieren Sie "UnaryOperator
import java.util.function.UnaryOperator;
public class MyUpperOperator implements UnaryOperator<String> {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}
main Wenn Sie die zuvor erstellte Kapitalkonvertierungsfunktion und die Zeichenfolge an die Druckmethode übergeben, werden sie in allen Großbuchstaben ausgegeben.
public static void main(String[] args) {
UnaryOperator<String> upperOperator = new MyUpperOperator();
print("hello world", upperOperator); // -> HELLO WORLD
}
Es verwendet eine funktionale Schnittstelle, aber es ist nur ein Strategiemuster.
Im vorherigen Beispiel ist tatsächlich ein leistungsfähigerer Schreibstil möglich.
Mit einer Funktion namens ** Methodenreferenz ** ist es möglich, eine Methode, deren Argument und Rückgabewert übereinstimmen, direkt zu übergeben, ohne explizit eine funktionale Schnittstelle zu implementieren.
Im Fall des vorherigen Beispiels kann die Methode, da sie "UnaryOperator toUpperCase ()
der String-Klasse
direkt der Instanz UnaryOperator <String>
zuweisen.
(Bei einer Methodenreferenz einer Instanzmethode wird das Empfängerobjekt als erstes Argument interpretiert. Siehe die folgende Syntax.)
In diesem Fall scheint der aufrufende Quellcode die Funktion als erstklassiges Objekt zu behandeln.
public static void main(String[] args) {
// UnaryOperator<String> upperOperator = new MyUpperOperator();
UnaryOperator<String> upperOperator = String::toUpperCase;
print("hello world", upperOperator); // -> HELLO WORLD
}
Es scheint, dass es die Anweisung invokeDynamic
der JVM verwendet.
Es scheint, dass die Klasse zur Laufzeit dynamisch generiert und gelöst wird, nicht zur Kompilierungszeit.
Notation von zwei aufeinanderfolgenden Semikolons. Der auf beiden Seiten des Semikolons beschriebene Inhalt kann je nach Art der Methode grob in vier Muster unterteilt werden.
Ziel | Grammatik | Beispiel |
---|---|---|
Klassenmethode | Name der Klasse::Name der Klassenmethode | String::toString |
Instanzmethode | Instanzname::Name der Instanzmethode | System.out::println |
Instanzmethode * | Name der Klasse::Name der Instanzmethode | String::toUpperCase |
Konstrukteur | Name der Klasse::new | String::new |
Das vorige Beispiel kann sehr kurz beschrieben werden. Die MyUpperOperator-Klasse wird nicht mehr benötigt.
public static void main(String[] args) {
print("hello world", String::toUpperCase); // -> HELLO WORLD
}
Außerdem erfordern viele der in Java8 hinzugefügten Stream-APIs eine funktionale Schnittstelle, sodass diese Art der Verarbeitung durchgeführt werden kann.
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "charlie", "alpha");
strings.stream()
.map(String::toUpperCase)// Function:In Großbuchstaben konvertieren
.forEach(System.out::println);// Consumer:Ausgabe
// BRAVO
// CHARLIE
// ALPHA
}
Es ist notwendig, die Methode im Voraus zu deklarieren, um damit umgehen zu können. Es ist gut, die bereitgestellten Methoden zu verwenden, aber Sie müssen Ihre eigene Verarbeitung einzeln als Methode deklarieren. Ich möchte die Methode wie ein Literal behandeln.
Bewertungsformelmechanismus, der einer Funktionsschnittstelle zugewiesen werden kann. Sie können eine Methode als Ausdruck schreiben, ohne die Methode zu deklarieren.
B. Funktion zum Hinzufügen eines Punkts zur Zeichenfolge
public static void main(String[] args) {
// UnaryOperator<String> upperOperator = String::toUpperCase;
UnaryOperator<String> periodOperator = (String s) -> { return s + "."; };
print("hello world", periodOperator); // -> hello world.
}
Dies ist die Grundform
(Formale Argumentzeichenfolge) -> {Verarbeitung der Body-Anweisung}
e.g.
(String s) -> { return s + "."; }
Verschiedene Beschreibungen können nur unter bestimmten Bedingungen weggelassen werden.
Ich werde es weglassen, weil ich denke, dass verschiedene Dinge herauskommen werden, wenn ich es nachschlage.
in diesem Fall
UnaryOperator<String> periodOperator = s -> s + ".";
public static void main(String[] args) {
print("hello world", s -> s + "."); // -> hello world.
}
public static void main(String[] args) {
List<String> strings = Arrays.asList("bravo", "", "charlie", "alpha");
strings.stream()
.filter(s -> !s.isEmpty()) // Predicate:Leerzeichen entfernen
.map(s -> s.substring(0, 1).toUpperCase() + s.substring(1)) // Function:Konvertieren Sie nur das erste Zeichen in Großbuchstaben
.forEach(System.out::println); // Consumer:Ausgabe
// Bravo
// Charlie
// Alpha
}
Ein Beispiel für Letzteres ist der am Anfang dieses Artikels erwähnte Prozess.
Sie können diesen Quellcode lesen und verwenden.
Die funktionale Programmierung wurde seit Java8 verbessert.
Überarbeitete 2. Ausgabe von Perfect Java: Book Guide | Technical Review Effektive Java 3rd Edition-Maruzen Publishing, ein spezialisierter Buchverlag für Wissenschaft, Technik, Medizin sowie Geistes- und Sozialwissenschaften
Recommended Posts