Wenn ich einen Ereignis-Listener mit einem Lambda hinzufüge, der eine überschreibbare Methode im Konstruktor aufruft, erhalte ich eine Warnung. Wenn ich eine Methodenreferenz verwende, bekomme ich keine Warnungen über überschreibbare Methoden oder lecke dies. Sollte ich Methodenverweise im Konstruktor vermeiden oder ist es sicher?
Hier ist ein einfaches Beispiel:
%Vor%Methodenreferenzen und Lambdas bewerten beide dasselbe, eine funktionale Schnittstelle:
Also, die zwei sind im Wesentlichen gleichwertig. Im Fall der Methodenreferenz ist das Ziel explizit this
und im Fall von Lambda ist es implizit this
. Ihre "warnende" ist also die gleiche. Die nächste Frage ist: Wem hat der Compiler falsch geraten? Ist die Warnung falsch oder fehlt eine Warnung?
Der Grund für die Warnung ist, dass das Lecken von this
aus dem Konstruktor einige große Gefahren birgt. Einer bezieht sich auf Multithreading: jede Speichersichtbarkeit, die Sie von% co_de erhalten% Feld Semantik (sowie einige andere Garantien) sind weg, wenn Sie final
von der Referenz auslaufen lassen. Die andere Sorge ist, dass die this
-Methode sofort die Methode auf addListener
aufruft, bevor der Konstruktor fertig ist. Das heißt, es wird eine Methode für ein teilweise konstruiertes Objekt aufgerufen. Das ist besonders problematisch für überschreibbare Methoden, weil es sein kann, dass dieser Konstruktor für die Oberklasse einer anderen Person ist und dass jemand anderes die betreffende Methode überschrieben hat. In diesem Fall rufen Sie die Methode für diese Unterklasse auf, deren Konstruktor noch nicht einmal gestartet werden konnte (da der Konstruktor einer Oberklasse zuerst ausgeführt wird).
Also, ja, die Warnung auf dem Lambda ist richtig. Und es sollte auch für die Methodenreferenz da sein.
Nein, das ist definitiv nicht sicher. Sie veröffentlichen this
, auf das der fremde Code zugreifen kann, bevor das Objekt vollständig erstellt wurde. Das Registrieren eines Listeners von einem Konstruktor ist immer ein No-No, ob Sie es über eine anonyme Klasse oder über einen Lambda oder eine Methodenreferenz tun. Ihr Beispiel entspricht dem Idiom, vor dem ich vor 12 Jahren gewarnt habe: Ссылка
Die Einbeziehung von Methodenreferenzen ist hier ein Ablenkungsmanöver; Das Problem besteht darin, dass Sie einen Verweis auf ein teilweise konstruiertes Objekt für Code bereitstellen, den Sie nicht steuern.
Der Compiler kann Sie nicht vor allem warnen; Nur weil es keine Warnung gibt, heißt das nicht, dass Ihr Code richtig ist:)
Tags und Links java java-8 lambda constructor