Selbst wenn Sie Lambda-Ausdrücke in Streams verwenden können, können Sie die Funktionsschnittstelle möglicherweise nicht für Ihre eigenen Funktionen nutzen. Für solche Leute möchte ich anhand eines einfachen Beispiels vorstellen, wie eine funktionale Schnittstelle auf eine selbst erstellte Funktion angewendet wird.
Es ist üblich, die Eigenschaften eines Objekts in ein anderes zu kopieren. Zu diesem Zeitpunkt ist es häufig der Fall, dass die Kopierbedingung nur festgelegt wird, wenn der Wert der Eigenschaft nicht null ist. Und wie in diesem Beispiel werden häufig Kopien verschiedener Typeneigenschaften in einer Reihe angeordnet. Es kann Fälle geben, in denen Sie auf diese Weise kopieren und einfügen können, aber ich möchte ein wenig darüber nachdenken. Erstellen wir eine allgemeine Funktion für den folgenden Code, um den Aufruf zu vereinfachen. Beachten Sie, dass getName () einen String zurückgibt und setName () einen String setzt. getFlag () gibt Boolean zurück und setFlag () setzt Boolean.
if(objA.getName()!=null) {
objB.setName(objA.getName());
}
if(objA.getFlag()!=null) {
objB.setFlag(objA.getFlag());
}
Ich hoffe du kannst es wie folgt schreiben. Mal sehen, wie es in Java erreicht wird.
setIfNotNull(value,func) {
if(value!= null) {
func(value);
}
}
setIfNotNull(objA.getName(),objB.setName);
setIfNotNull(objA.getFlag(),objB.setFlag);
Im obigen Pseudocode zeigt func eine Methode, aber wie sollte sie in Java ausgedrückt werden? Eine Schnittstelle gibt eine Methode an. Auch dies kann mit einer Schnittstelle möglich sein.
public interface SetNameInterface {
void setName(String value);
}
public Class ObjB implements SetNameInterface{
void setName(String name);
}
public void setIfNotNull(String value,SetNameInterface obj) {
if(value!= null) {
obj.setName(value);
}
}
setIfNotNull(objA.getName(),objB);
Es war möglich, setName () zu unterstützen, aber es ist klar, dass es nicht mit setFlag () kompatibel ist. Diese Methode ist intuitiv, funktioniert aber nicht.
Weil wir setName () und setFlag () von setIfNotNull () mit dem gemeinsamen Funktionsnamen func aufrufen möchten. Wie wäre es mit einem Objekt mit func als Schnittstelle für setName () und setFlag ()?
public Class ObjB {
public void setName(String name) {
System.out.println("OnjB.setName:"+name);
}
public void setFlag(Boolean flag) {
System.out.println("OnjB.setFlag:"+flag);
}
}
public interface FuncInterface<T> {
void func(T value);
}
public class ObjBSetName implements FuncInterface<String> {
ObjB obj;
public ObjBSetName(ObjB obj) {
this.obj = obj;
}
@Override
public void func(String value) {
obj.setName(value);
}
}
public class ObjBSetFlag implements FuncInterface<Boolean> {
ObjB obj;
public ObjBSetFlag(ObjB obj) {
this.obj = obj;
}
@Override
public void func(Boolean value) {
obj.setFlag(value);
}
}
public <T>void setIfNotNull(T value,FuncInterface<T> obj) {
if(value!= null) {
obj.func(value);
}
}
setIfNotNull(objA.getName(),new ObjBSetName(objB));
setIfNotNull(objA.getFlag(),new ObjBSetFlag(objB));
ObjBSetName und ObjBSetFlag verfügen beide über Funktionsfunktionen, die in der FuncInterface-Schnittstelle definiert sind. Wenn die Funktion func aufgerufen wird, werden die ursprüngliche Verarbeitung objB.setName () und objB.setFlag () aufgerufen. In der FuncInterface-Schnittstelle wird der Typ des an die Methode übergebenen Parameters als generischer Typ deklariert (in diesem Fall T). Entsprechend ändert setIfNotNull () auch value und obj, um generische Typen zu verwenden.
Ich habe erreicht, was ich damit machen möchte, aber es ist überflüssig, ObjBSetName und ObjBSetFlag vorzubereiten. Verwenden wir eine anonyme Klasse.
Wie schreibe ich eine anonyme Klasse
neuer übergeordneter Klassen- oder Schnittstellenname () { Anonymer Klasseninhalt (Feld- und Methodendefinitionen) };
Denn es ist
var objBSetName = new FuncInterface<String>() {
@Override
public void func(String value) {
objB.setName(value);
}
};
var objBSetFlag = new FuncInterface<Boolean>() {
@Override
public void func(Boolean value) {
objB.setFlag(value);
}
};
Schreiben, Der Anruf ist
setIfNotNull(objA.getName(),objBSetName);
setIfNotNull(objA.getFlag(),objBSetFlag);
Es wird sein. Innerhalb der anonymen Klasse können Sie direkt auf das Objekt objB verweisen.
Für Schnittstellen mit nur einer definierten Funktion kann die anonyme Klasse durch einen Lambda-Ausdruck ersetzt werden
FuncInterface<String> objBSetName = (v) -> objB.setName(v);
FuncInterface<Boolean> objBSetFlag = (v) -> objB.setFlag(v);
Kann umgeschrieben werden als. Der Lambda-Ausdruck hat nicht die Notationsfunktion, implementiert jedoch die in FuncInterface definierte Funktion. Es ist schwer zu erkennen, dass func im Lambda-Ausdruck verschwunden ist, aber Sie können es verstehen, indem Sie es mit der anonymen Klasse vergleichen.
Lassen Sie die Variable weiter weg,
setIfNotNull(objA.getName(),(v) -> objB.setName(v));
setIfNotNull(objA.getFlag(),(v) -> objB.setFlag(v));
Kann zusammengefasst werden als.
Die Deklaration der Schnittstelle FuncInterface ist übrigens eigentlich eine funktionale Schnittstelle. Der Verbraucher existiert bereits, also ersetzen wir ihn durch diesen. (Bevor Sie eine eigene Schnittstelle erstellen, sollten Sie prüfen, ob die bereitgestellte Funktionsschnittstelle verwendet werden kann.)
public <T>void setIfNotNull(T value,Consumer<T> obj) {
if(value!= null) {
obj.accept(value);
}
}
Da es ein Argument gibt, kann der Aufruf außerdem unter Verwendung einer Methodenreferenz erfolgen.
setIfNotNull(objA.getName(),objB::setName);
setIfNotNull(objA.getFlag(),objB::setFlag);
Es wird sein. Es war ziemlich ordentlich.
Dieses Mal habe ich mit einem kleinen Beispiel erklärt, aber Sie können sehen, dass "Verarbeitung" an die Funktion übergeben werden kann. Ich denke. Die Deklaration dafür ist die "Funktionsschnittstelle". Sie haben sich vielleicht schon vorgestellt, dass Sie damit ein "Strategiemuster" erzielen könnten. Bitte wenden Sie es auf Ihr Programm an und verwenden Sie es erneut.
Recommended Posts