lateinit
in Kotlin gibt es so, dass Sie nicht nullable Typen für Variablen haben können, die Sie nicht initialisieren können, sobald die Klasse, die sie enthält, erstellt wird.
Wenn Sie in Ihrem Beispiel lateinit
nicht verwenden, müssen Sie die subject
Nullable machen, da sie mit einem Wert initialisiert werden muss.
public class MyTest {
var subject: TestSubject? = null
}
Dies würde Sie zwingen, jedes Mal, wenn es null Kontrollen zu tun verwenden, was hässlich ist, so dass Sie es als lateinit
stattdessen markieren können.
In Java, Sie haben dieses Problem nicht wirklich, da alles NULL-Werte zulässt, und ein nicht initialisierte Feld zu erklären ist nichts Besonderes:
public class JavaTest {
TestSubject subject;
}
Diese initialisiert subject
zu null
, so ist es praktisch gleichwertig zu dem nicht-lateinit
Kotlin-Beispiel.
Der einzige wirkliche Unterschied zwischen der lateinit
Version in Kotlin und der Java-Version ist, dass Sie eine spezifischere Ausnahme erhalten, wenn eine nicht initialisierte Eigenschaft in Kotlin zuzugreifen versuchen, nämlich ein UninitializedPropertyAccessException
, die es einfacher debuggen machen als zu haben, Suchen Sie nach der Ursache für ein generisches NullPointerException
.
Wenn Sie wirklich dieses leicht unterschiedliches Verhalten wollen, könnten Sie Ihre Java-Objekte in einer Art Wrapper wickeln, aber ich glaube nicht, dass der syntaktische Aufwand lohnen würde, dies zu tun.Ein sehr einfacher (nicht Thread-sicher, zum Beispiel) Weg, dies zu tun wäre:
Haben Sie eine generische Wrapper-Klasse für Eigenschaften:
public class Property<T> {
private T value = null;
public T get() {
if (value == null)
throw new UninitializedPropertyAccessException("Property has not been initialized");
return value;
}
public void set(T value) {
if (value == null)
throw new IllegalArgumentException("Value can't be null");
this.value = value;
}
}
Verwenden Sie diesen Wrapper in Ihren Klassen:
public class JavaTest {
Property<TestSubject> subject = new Property<>();
}
Und dann würde dieser Gebrauch Sie die nicht initialisierten Ausnahme geben:
JavaTest test = new JavaTest();
test.subject.get();
Und dieser würde ru n fein:
JavaTest test = new JavaTest();
test.subject.set(new TestSubject());
test.subject.get();
Edit: dies sehr ähnlich ist, wie lateinit
Werke in Kotlin, wenn Sie den Bytecode von Ihrem Beispiel Java dekompilieren, das ist, was man bekommt:
public final class MyTest {
@NotNull
public TestSubject subject;
@NotNull
public final TestSubject getSubject() {
TestSubject var10000 = this.subject;
if(this.subject == null) {
Intrinsics.throwUninitializedPropertyAccessException("subject");
}
return var10000;
}
public final void setSubject(@NotNull TestSubject var1) {
Intrinsics.checkParameterIsNotNull(var1, "<set-?>");
this.subject = var1;
}
}
Im Grunde legt der Compiler den Code für die Überprüfung des Eigenschaftszugriffs innerhalb der Klasse selbst (+ verwendet einige Hilfsmethoden) anstatt einen Wrapper zu verwenden, was effizienter ist.
Verwenden Sie einfach java 'getter', in dem Sie überprüfen, ob es initialisiert ist, wenn nicht ein –