Implementieren rekursive lambda-Funktion, die mit Java 8
Java 8 eingeführten lambda-Funktionen und ich will etwas umsetzen, wie Fakultät:
IntToDoubleFunction fact = x -> x == 0 ? 1 : x * fact.applyAsDouble(x-1);
Zusammenstellung gibt
error: variable fact might not have been initialized
Wie kann ich die Verweis-Funktion selbst. Klasse ist anonym, aber-Instanz existiert: Es heißt fact
.
InformationsquelleAutor user2678835 | 2013-10-17
Du musst angemeldet sein, um einen Kommentar abzugeben.
Normalerweise verwende ich (einmal-für-alle-funktionelle-Schnittstellen definiert) generische helper-Klasse die wraps die variable der funktionalen Schnittstelle geben.
Dieser Ansatz löst das problem mit der lokalen Initialisierung der Variablen und erlaubt den code zu schauen mehr klar.
In dieser Frage wird der code wie folgt Aussehen:
InformationsquelleAutor Andrey Morozov
Eine Möglichkeit ist das erstellen einer sekundären Funktion,
helper
, das nimmt eine Funktion und eine Zahl als argument, und schreiben Sie dann die Funktion, die Sie wirklich wollen,fact = helper(helper,x)
.Etwa so:
Diese scheint mir etwas eleganter als sich auf Ecke Fall Semantik wie ein Verschluss, zeichnet einen Verweis auf eine veränderliche Struktur, oder self-Referenz mit einer Warnung vor der Möglichkeit, dass "möglicherweise nicht initialisiert werden."
Immer noch, es ist keine perfekte Lösung, weil der Java Typ-system-Generika kann nicht garantieren, dass
f
ist, ist das argumentfactHelper
, ist von der gleichen Art wiefactHelper
(d.h. gleicher input-Typen und Ausgabe-Arten), denn das würde eine unendlich geschachtelte generische.So, stattdessen eine sicherere Lösung sein könnte:
Den code, der Geruch, die aus der
factHelper
's weniger-als-perfekte generische Typ ist jetzt enthalten (oder, ich wage zu sagen, gekapselt), die innerhalb der lambda, sicherzustellen, dassfactHelper
wird nie aufgerufen werden, unwissentlich.InformationsquelleAutor rationalis
Lokale und anonyme Klassen, sowie lambdas, erfassen der lokalen Variablen von Wert, wenn Sie erstellt werden. Daher ist es für Sie unmöglich, sich selbst durch die Erfassung einer lokalen Variablen, weil Sie den Wert für verweist auf sich selbst existiert noch nicht an der Zeit, die Sie erstellt werden.
Code in lokale und anonyme Klassen können immer noch finden sich mit
this
. Allerdingsthis
in einen lambda-Ausdruck bezieht sich nicht auf den lambda; es bezieht sich auf diethis
von außen Umfang.Können Sie erfassen eine veränderbare Datenstruktur, wie ein array, statt:
aber kaum als eine elegante Lösung.
InformationsquelleAutor newacct
Wenn Sie feststellen, selbst benötigen, das zu tun diese Art der Sache oft, eine andere option ist das erstellen eines Helfer-Schnittstelle und Methode:
Und dann schreiben:
(Während ich dies Tat, generisch mit Referenz-Typen, können Sie auch primitiv-spezifischen Versionen).
Dieser leiht sich von einem alten trick in Die Kleine Lisper für die Herstellung Unbenannte Funktionen.
Ich bin mir nicht sicher, ob ich das jemals tun dies in der Produktion code, aber es ist interessant...
InformationsquelleAutor Ian Robertson
Einer Lösung ist, um zu definieren, diese Funktion als INSTANZ-Attribut.
Diese Antwort bekräftigt die Frage. Nach unten Stimmen.
InformationsquelleAutor user2678835
Andere version mit Akkumulator, so dass die Rekursion optimiert werden können.
Verschoben Generic interface definition.
InformationsquelleAutor user2678835
Definieren Sie eine rekursive lambda als eine Instanz-oder Klassenvariable:
Beispiel:
Drucke
120.0
.Aber es funktioniert immer noch auf Instanz - /Klassenvariablen, richtig?
In einfachen Fällen, ja, aber Sie erhalten eine Warnung über
factorial
möglicherweise nicht initialisiert werden. Ich glaube nicht, dass es tatsächlich ein problem in diesem Beispiel, da die lambda kann nicht aufgerufen werden, bevor es initialisiert wird, aber ich bin sicher, dass jemand kommen könnte mit einem ausreichend komplizierten Beispiel, endete die Beobachtung ein Feld in einem nicht initialisierten Zustand. Irgendwann scheint es vorzuziehen, Namen und Methoden-Referenzen. Siehe meine Antwort hier: stackoverflow.com/a/21652054/1441122"Kann keinen Verweis auf ein Feld, bevor es definiert ist"?
InformationsquelleAutor assylias
InformationsquelleAutor Danil Gaponov
Folgende funktioniert, aber es tut geheimnisvoll erscheinen.
InformationsquelleAutor Jerrolds
Etwas wie die erste Antwort ...
InformationsquelleAutor Rene.v.P.
Hörte ich auf der JAX in diesem Jahr, dass "lambads unterstützen keine Rekursion". Was ist gemeint mit dieser Aussage ist, dass "this" innerhalb der lambda beziehen sich immer auf die umgebende Klasse.
Aber ich schaffte es zu definieren - zumindest so verstehe ich den Begriff "Rekursion" - eine rekursive lambda-und es geht so:
Speichern diese in einer Datei "Recursion.java" und die beiden Befehle "javac Recursion.java" und "java Rekursion" es funktionierte für mich.
Der clou ist, dass die Schnittstelle, die lambda hat zu implementieren, wie eine Feld-variable in der umgebenden Klasse. Die lambda kann beziehen sich auf dieses Feld und das Feld nicht implizit final.
InformationsquelleAutor beck
Können Sie auch definieren Sie als eine lokale variable, indem Sie erstellen eine Letzte Reihe von Größe (sagen die Funktion[]) und weisen Sie dann die Funktion element 0. Lassen Sie mich wissen, wenn Sie die genaue syntax
InformationsquelleAutor Victor Grazi
Angesichts der Tatsache, dass "dieser" in den lambda-Ausdruck bezieht sich auf die enthaltende Klasse, die folgenden kompiliert ohne Fehler (mit zusätzlichen Abhängigkeiten, natürlich):
InformationsquelleAutor Rebel Geek
Andere rekursive Fakultät mit Java 8
InformationsquelleAutor Dmytro Chopenko
Stieß auf diese Frage bei einem Vortrag über Lambda-Ausdrücke, die verwendet Fibonacci als einen möglichen Anwendungsfall.
Können Sie eine rekursive lambda-Ausdruck wie diesem:
Was müssen Sie beachten?
Lambda-Ausdrücke werden ausgewertet, auf die Ausführung -> Sie können rekursiv sein
Mittels eines lambda-variable innerhalb einer anderen lambda-erfordert die
variable initialisiert werden -> vor der Definition eine rekursive lambda-Sie
definieren Sie es mit einem foo-Wert
mit einem lokalen lambda-Variablen innerhalb eines lambda-erfordert die variable
endgültig, so kann es nicht neu definiert werden -> verwenden Sie eine Klasse/Objekt
variable für die lambda - wie es bei der Initialisierung mit einem Standardwert
InformationsquelleAutor 000000000000000000000
@IanRobertson Schön gemacht, in der Tat, können Sie die statische 'factory' in den Körper des interface selbst, also die Kapselung vollständig:
Dies ist die sauberste Lösung/Antwort, die ich bisher gesehen habe ... vor allem, da der Aufruf von "tatsächlich" geschrieben "natürlich": fac.gelten(n) das ist, was Sie erwarten würden, um zu sehen, für eine einfachen Funktion wie fac()
InformationsquelleAutor Larry Cable
Antwort ist : Sie haben eine diese vor dem Namen der variable aufrufen applyAsDouble Funktion :-
wenn Sie die Tatsache Finale auch, es wird funktionieren
Können wir mithilfe der funktionellen Schnittstelle UnaryOperator hier. Ein unärer operator, der immer wieder seine input-argument.
1) fügen Sie Einfach diese. vor dem Namen der Funktion, wie in:
Diese wird hep zu vermeiden "kann Nicht auf ein Feld, bevor es definiert ist".
2) Wenn Sie lieber eine statische Feld, ersetzen Sie diesen durch den Namen der Klasse:
InformationsquelleAutor Arundev
Das problem ist, dass lambda-Funktionen bedienen möchten, auf
final
Variablen, die wir brauchen, eine veränderlicheFunction
-Referenz, die ausgetauscht werden können mit unseren lambda.Der einfachste trick scheint zu sein, definieren Sie die variable als eine member-variable, und der compiler sich nicht beschweren.
Änderte ich mein Beispiel zu verwenden
IntUnaryOperator
stattIntToDoubleFunction
werden, da wir uns nur aufIntegers
sowieso hier.InformationsquelleAutor tomaj
Hier ist eine Lösung, die sich nicht auf eine Nebenwirkung. Um den Zweck zu interessanten, zu sagen, dass Sie möchten, um Abstrakt über die Rekursion (sonst ist das Instanz-Feld-Lösung durchaus gültig ist).
Der trick ist die Verwendung einer anonymen Klasse, um den "this" - Referenz:
InformationsquelleAutor JbGi
Während meiner tests, das ist das beste, was ich erreichen konnte für die lokale rekursive Lambda-Ausdrücke.
Sie können verwendet werden, in die Bäche als gut, aber wir verlieren die Leichtigkeit des Ziels eingeben.
InformationsquelleAutor leonel dossantos
Erstellen Sie eine rekursive Funktion, die mithilfe dieser Klasse:
Und dann können Sie keine funktionalen Oberfläche in nur 1 Zeile über, eine lambda und der definition der funktionalen Schnittstelle wie folgt:
Ich fand es sehr intuitiv und einfach zu bedienen.
InformationsquelleAutor Jose Da Silva
Habe ich nicht eine Java8-compiler praktisch, so kann nicht testen, meine Antwort. Aber wird es funktionieren, wenn Sie die Definition des "Tat' variable Letzte?
InformationsquelleAutor shrini1000