Wenn Sie in Kotlin keine Klasseneigenschaft innerhalb des Konstruktors oder oben im Klassenkörper initialisieren möchten, haben Sie grundsätzlich diese beiden Optionen (aus der Sprachreferenz):
lazy () ist eine Funktion, die ein Lambda verwendet und eine Instanz von Lazy zurückgibt, die als Delegat für die Implementierung einer Lazy-Eigenschaft dienen kann: Der erste Aufruf von get () führt das an Lazy () übergebene Lambda aus und merkt sich das Ergebnis und nachfolgende Aufrufe Um () zu erhalten, geben Sie einfach das gespeicherte Ergebnis zurück.
Beispiel
public class Hello { val myLazyString: String by lazy { "Hello" } }
So den ersten Anruf und die subquential Anrufe, wo auch immer es ist, zu myLazyString zurückkehren wird „Hallo“
Normalerweise müssen Eigenschaften, die als Nicht-Null-Typ deklariert sind, im Konstruktor initialisiert werden. Dies ist jedoch ziemlich oft nicht bequem. Beispielsweise können Eigenschaften durch Abhängigkeitsinjektion oder in der Setup-Methode eines Komponententests initialisiert werden. In diesem Fall können Sie im Konstruktor keinen Initialisierer ungleich Null angeben, möchten jedoch weiterhin Nullprüfungen vermeiden, wenn Sie auf die Eigenschaft im Hauptteil einer Klasse verweisen.
Um diesen Fall zu behandeln, können Sie die Eigenschaft mit dem Modifikator lateinit markieren:
public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() } }
Der Modifikator kann nur für var-Eigenschaften verwendet werden, die im Hauptteil einer Klasse deklariert sind (nicht im primären Konstruktor), und nur, wenn die Eigenschaft keinen benutzerdefinierten Getter oder Setter hat. Der Typ der Eigenschaft darf nicht null sein und darf kein primitiver Typ sein.
Wie kann man also richtig zwischen diesen beiden Optionen wählen, da beide das gleiche Problem lösen können?
quelle
lateinit
das Hintergrundfeld mit der Sichtbarkeit des Setters verfügbar gemacht wird, sodass die Art und Weise, wie auf die Eigenschaft von Kotlin und Java aus zugegriffen wird, unterschiedlich ist. Und aus Java-Code kann diese Eigenschaft auchnull
ohne Überprüfung in Kotlin festgelegt werden. Daherlateinit
ist nicht für die verzögerte Initialisierung, sondern für die Initialisierung nicht unbedingt aus Kotlin-Code.Lazy
+ verwenden,.isInitialized()
um dies zu tun. Ich denke, es gibt keine einfache Möglichkeit, eine solche Immobilie zu überprüfen,null
da garantiert wird, dass Sie nicht davon profitierennull
können. :) Siehe diese Demo .by lazy
verwenden, um die Erstellungszeit oder die Laufzeit zu verlangsamen?lateinit
, die Verwendung vonnull
für nicht initialisierten Wert zu umgehen . Anders als dasnull
sollte nie verwendet werden, und mitlateinit
Nullen kann weg beseitigt werden. So liebe ich Kotlin :)Zusätzlich zu seiner
hotkey
guten Antwort wähle ich in der Praxis wie folgt zwischen den beiden:lateinit
ist für die externe Initialisierung gedacht: Wenn Sie externes Material benötigen, um Ihren Wert durch Aufrufen einer Methode zu initialisieren.zB telefonisch:
In diesem Fall werden
lazy
nur objektinterne Abhängigkeiten verwendet.quelle
Sehr kurze und prägnante Antwort
lateinit: In letzter Zeit werden Nicht-Null-Eigenschaften initialisiert
Im Gegensatz zur verzögerten Initialisierung erkennt lateinit den Compiler, dass der Wert der Nicht-Null-Eigenschaft nicht in der Konstruktorstufe gespeichert ist, um normal zu kompilieren.
faule Initialisierung
by lazy kann sehr nützlich sein, wenn schreibgeschützte (val) Eigenschaften implementiert werden, die eine Lazy-Initialisierung in Kotlin durchführen.
by faul {...} führt seinen Initialisierer dort aus, wo die definierte Eigenschaft zuerst verwendet wird, nicht seine Deklaration.
quelle
lateinit vs faul
lateinit
i) Verwenden Sie es mit der veränderlichen Variablen [var]
ii) Nur mit nicht nullbaren Datentypen zulässig
iii) Es ist ein Versprechen an den Compiler, dass der Wert in Zukunft initialisiert wird.
HINWEIS : Wenn Sie versuchen, auf die Variable lateinit zuzugreifen , ohne sie zu initialisieren, wird eine UnInitializedPropertyAccessException ausgelöst.
faul
i) Die verzögerte Initialisierung wurde entwickelt, um eine unnötige Initialisierung von Objekten zu verhindern.
ii) Ihre Variable wird nur initialisiert, wenn Sie sie verwenden.
iii) Es wird nur einmal initialisiert. Wenn Sie es das nächste Mal verwenden, erhalten Sie den Wert aus dem Cache-Speicher.
iv) Es ist threadsicher (Es wird in dem Thread initialisiert, in dem es zum ersten Mal verwendet wird. Andere Threads verwenden denselben Wert, der im Cache gespeichert ist).
v) Die Variable kann nur val sein .
vi) Die Variable kann nur nicht nullbar sein .
quelle
Zusätzlich zu all den tollen Antworten gibt es ein Konzept namens Lazy Loading:
Bei ordnungsgemäßer Verwendung können Sie die Ladezeit Ihrer Anwendung verkürzen. Die Implementierung von Kotlin besteht darin,
lazy()
den erforderlichen Wert bei Bedarf in Ihre Variable zu laden.Lateinit wird jedoch verwendet, wenn Sie sicher sind, dass eine Variable nicht null oder leer ist und initialisiert wird, bevor Sie sie verwenden -eg in
onResume()
Methode für Android-, und Sie sie daher nicht als nullbaren Typ deklarieren möchten.quelle
onCreateView
,onResume
und andere mitlateinit
, aber manchmal Fehler aufgetreten gibt (weil einige Ereignisse früher begonnen).by lazy
Kann also vielleicht ein angemessenes Ergebnis liefern. Ich verwendelateinit
für Nicht-Null-Variablen, die sich während des Lebenszyklus ändern können.Oben ist alles richtig, aber eine der Tatsachen einfache Erklärung LAZY ---- Es gibt Fälle, in denen Sie die Erstellung einer Instanz Ihres Objekts bis zu ihrer ersten Verwendung verzögern möchten. Diese Technik ist als verzögerte Initialisierung oder verzögerte Instanziierung bekannt. Der Hauptzweck der verzögerten Initialisierung besteht darin, die Leistung zu steigern und den Speicherbedarf zu verringern. Wenn das Instanziieren einer Instanz Ihres Typs einen hohen Rechenaufwand verursacht und das Programm sie möglicherweise nicht tatsächlich verwendet, sollten Sie die Verschwendung von CPU-Zyklen verzögern oder sogar vermeiden.
quelle
Wenn Sie einen Spring-Container verwenden und ein nicht nullbares Bean-Feld initialisieren möchten,
lateinit
ist dies besser geeignet.quelle
@Autowired lateinit var myBean: MyBean
Wenn Sie eine unveränderliche Variable verwenden, ist es besser, mit
by lazy { ... }
oder zu initialisierenval
. In diesem Fall können Sie sicher sein, dass es bei Bedarf und höchstens einmal initialisiert wird.Wenn Sie eine Nicht-Null-Variable möchten, deren Wert sich ändern kann, verwenden Sie
lateinit var
. In Android Entwicklung können Sie später initialisieren es in solchen Ereignissen wieonCreate
,onResume
. Beachten Sie, dass ein Aufruf der REST-Anforderung und der Zugriff auf diese Variable zu einer Ausnahme führen kannUninitializedPropertyAccessException: lateinit property yourVariable has not been initialized
, da die Anforderung schneller ausgeführt werden kann, als diese Variable initialisieren könnte.quelle