Ist es möglich, eine Methodenreferenz (z. B. SomeClass::someMethod
) in eine MethodHandle
-Instanz zu konvertieren? Ich möchte die Vorteile der Kompilierzeitprüfung (die sicherstellen, dass die Klasse und Methode vorhanden ist) sowie die Möglichkeit, die Methode mit der MethodHandle
API zu überprüfen.
Anwendungsfall: Ich habe Code, der genau dann ausgeführt werden muss, wenn die Anfrage nicht von einer bestimmten Methode ausgelöst wurde (um eine endlose Rekursion zu vermeiden). Ich möchte eine Kompilierzeitprüfung, um sicherzustellen, dass die Klasse / Methode existiert, aber eine Laufzeitprüfung, um den Aufrufer mit der Methode zu vergleichen.
Zur Erinnerung: Ist es möglich, einen Methodenverweis in ein MethodHandle
umzuwandeln?
Nun, wenn Sie sich die zusätzlichen Kosten und Sicherheitsaspekte leisten können, können Sie ein Serializable
funktional interface
verwenden und die serialisierte Form der Methodenreferenzinstanz dekodieren, um das Ziel zu finden, wie in diese Antwort oder wieder mit diese Frage und ihre Antworten aufgekommen ist .
Sie sollten jedoch Ihr Software-Design wirklich überdenken. "Endlose Rekursion vermeiden" sollte nicht durch Dekodieren irgendeiner Art von Parameterobjekt behoben werden, insbesondere nicht, wenn angenommen wird, dass dieser tatsächliche Argumentwert den Aufrufer Ihrer Methode darstellt. Wie würdest du jemals diese seltsame Beziehung erzwingen?
Selbst eine einfache Codeänderung wie das Verweisen auf eine Methode, die an die andere Methode delegiert wird, würde Ihre Prüfung unterbrechen. Hier ist ein einfaches Beispiel, das die subtilen Probleme mit Ihrem Ansatz zeigt:
%Vor%Wenn Sie dieses Programm ausführen, wird etwas wie folgt gedruckt:
%Vor% zeigt, dass die Methodenreferenz in der generierten Instanz nicht die erwartete SimpleTest::process
ist, sondern stattdessen SimpleTest::lambda$MR$main$process$a9318f35
, die schließlich process
aufruft. Der Grund ist, dass einige Operationen (hier varargs -Verarbeitung) nicht von der generierten interface
-Instanz ausgeführt werden, sondern stattdessen von einer synthetischen Methode, so wie Sie run((a,b)-> SimpleTest.process(a,b))
geschrieben haben. Der einzige Unterschied ist der Name der synthetischen Methode.
Sie sollten keine Software entwerfen, die sich auf solch fragile Selbstbeobachtung stützt. Wenn Sie die Rekursion vermeiden möchten, genügt ein einfacher ThreadLocal
-Flag, der angibt, ob Sie sich bereits in Ihrer spezifischen Methode befinden. Aber es könnte sich lohnen, sich selbst zu fragen, warum Ihre API überhaupt eine endlose Rekursion provoziert; es scheint etwas grundsätzlich falsch zu sein ...
Tags und Links java java-8 method-reference methodhandle