Wie überprüfe ich, ob eine lateinit-Variable initialisiert wurde?

425

Ich frage mich, ob es eine Möglichkeit gibt, zu überprüfen, ob eine lateinitVariable initialisiert wurde. Zum Beispiel:

class Foo() {

    private lateinit var myFile: File

    fun bar(path: String?) {
        path?.let { myFile = File(it) }
    }

    fun bar2() {
        myFile.whateverMethod()
        // May crash since I don't know whether myFile has been initialized
    }
}
Mathew Hany
quelle
3
Vielleicht müssen Sie die Eigenschaft nullbar machen (Typ ändern in File?) und stattdessen überprüfen, ob sie null ist?
Marcin Koziński
1
Nun, ich habe das tatsächlich versucht und es wird den Trick machen, aber ich muss die allSeriesVar bearbeiten seriesDir?.listFiles()?.map { it.name }?.toTypedArray(), was nicht sehr "hübsch" ist
Mathew Hany
1
Sie können einen einfachen alten Null-Check durchführen, und Smart Cast macht ihn hübscher. if (seriesDir != null) { allSeries = seriesDir.listFiles().map { it.name }.toTypedArray() }
Marcin Koziński
Bitte erwägen Sie, aktuellere Antworten zu
Misanthrope

Antworten:

973

lateinitIn Kotlin 1.2 gibt es eine Verbesserung, mit der der Initialisierungsstatus der lateinitVariablen direkt überprüft werden kann:

lateinit var file: File    

if (this::file.isInitialized) { ... }

Siehe die Ankündigung im JetBrains-Blog oder den KEEP-Vorschlag .

UPDATE: Kotlin 1.2 wurde veröffentlicht. lateinitVerbesserungen finden Sie hier:

xsveda
quelle
3
@ fer.marino: Nun, Kotlin 1.2 erlaubt es Ihnen tatsächlich, lateinitauch für lokale Variablen zu verwenden, siehe kotlinlang.org/docs/reference/…
xsveda
9
this :: lateinitVar.isInitialized
vihkat
17
Was bedeutet ::vorher file?
Malwinder Singh
5
@MalwinderSingh erstellt eine Mitgliedsreferenz oder eine Klassenreferenz.
notGeek
5
Jetzt in Kotlin verliebt
Naveed Ahmad
44

Mit der .isInitializedEigenschaft kann der Initialisierungsstatus einer lateinit-Variablen überprüft werden.

if(::file.isInitialized){
    //File is initialized
}else{
    //File is not initialized
}
Nikhil Katekhaye
quelle
Dies gibt keine Antwort auf die Frage. Um einen Autor zu kritisieren oder um Klärung zu bitten, hinterlassen Sie einen Kommentar unter seinem Beitrag. - Aus der Überprüfung
gforce301
2
@ gforce301 Es wird definitiv zur Überprüfung verwendet.
Nikhil Katekhaye
39

Versuchen Sie es zu verwenden und Sie erhalten eine, UninitializedPropertyAccessExceptionwenn es nicht initialisiert ist.

lateinitist speziell für Fälle gedacht, in denen Felder nach der Erstellung, jedoch vor der tatsächlichen Verwendung initialisiert werden (ein Modell, das die meisten Injection-Frameworks verwenden). Wenn dies nicht Ihr Anwendungsfall ist, ist dies lateinitmöglicherweise nicht die richtige Wahl.

EDIT: Basierend auf dem, was Sie tun möchten, würde so etwas besser funktionieren:

val chosenFile = SimpleObjectProperty<File?>
val button: Button

// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())
Kiskae
quelle
Ich habe eine JavaFX-Anwendung und eine Schaltfläche, die immer deaktiviert wird, es sei denn, eine Variable (die ist lateinit) wurde initialisiert. Mit anderen Worten: Ich möchte, dass die Schaltfläche deaktiviert wird, solange die Variable nicht initialisiert wurde. Gibt es eine gute Möglichkeit, das zu tun?
Mathew Hany
@MathewHany Wie würde es normal initialisiert werden? Vielleicht möchten Sie sich Property Getter / Setter und eine SimpleBooleanProperty ansehen, die Sie an die deaktivierte Eigenschaft der Schaltfläche binden können
Kiskae
1
Um genauer zu sein, ich habe eine einfache App, die 4 Schaltflächen enthält. Die erste Schaltfläche öffnet ein DirectoryChooser-Dialogfeld und die anderen 3 werden deaktiviert. Wenn der Benutzer ein Verzeichnis auswählt, stehen dem Benutzer alle anderen Schaltflächen zur Verfügung.
Mathew Hany
@MathewHany Sie können dies nativ implementieren, indem Sie eine SimpleObjectProperty verwenden, um die ausgewählte Datei zu speichern, und dann die isNullBindung verwenden, um die anderen Schaltflächen zu deaktivieren.
Kiskae
1
kotlinlang.org/docs/reference/… xsveda Antwort ist aktueller
Serge
17

Sie können dies einfach tun, indem Sie:

::variableName.isInitialized

oder

this::variableName.isInitialized

Aber wenn Sie sich in einem Zuhörer oder einer inneren Klasse befinden, tun Sie Folgendes:

this@YourClassName::variableName.isInitialized

Hinweis: Die obigen Anweisungen funktionieren einwandfrei, wenn Sie sie in dieselbe Datei (dieselbe Klasse oder innere Klasse) schreiben, in der die Variable deklariert ist. Dies funktioniert jedoch nicht, wenn Sie die Variable einer anderen Klasse (nicht der Oberklasse oder deklariert in) überprüfen möchten eine andere Datei) , zum Beispiel:

class Test {
    lateinit var str:String
}

Und um zu überprüfen, ob str initialisiert ist:

Geben Sie hier die Bildbeschreibung ein

Was wir hier tun, um auf das Feld strder TestKlasse in der Test2Klasse zuzugreifen . Und wir bekommen ein Fehler-Backing-Feld von var ist derzeit nicht zugänglich. Überprüfen Sie eine bereits aufgeworfene Frage dazu.

Suraj Vaishnav
quelle
12

Akzeptierte Antwort gibt mir einen Compilerfehler in Kotlin 1.3+, ich musste das thisSchlüsselwort vorher explizit erwähnen ::. Unten ist der Arbeitscode.

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}
Sazzad Hissain Khan
quelle
Ich verwende eine lokale Init-Variable, wenn ich diese Prüfung verwende, die einen Fehler wie eine ungelöste Referenz
ergibt
3

So überprüfen Sie, ob a lateinit varinitialisiert wurde oder nicht, verwenden Sie a .isInitializedfür den Verweis auf diese Eigenschaft:

if (foo::bar.isInitialized) {
    println(foo.bar)
}

Diese Überprüfung ist nur für die Eigenschaften verfügbar, auf die lexikalisch zugegriffen werden kann, dh die im selben Typ oder in einem der äußeren Typen oder auf oberster Ebene in derselben Datei deklariert sind.

Andy
quelle
1
Was bedeutet ::vorher bar?
Malwinder Singh
@ Malwinder Singh "erstellt eine Mitgliederreferenz oder eine Klassenreferenz" - Kotlin Doc
DMonkey
0
kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized

Bytecode sagt ... bla bla ..

public final static synthetic access$getClientKeypair$p(Lcom/takharsh/ecdh/MainActivity;)Ljava/security/KeyPair;

`L0
LINENUMBER 11 L0
ALOAD 0
GETFIELD com/takharsh/ecdh/MainActivity.clientKeypair : Ljava/security/KeyPair;
DUP
IFNONNULL L1
LDC "clientKeypair"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwUninitializedPropertyAccessException (Ljava/lang/String;)V
    L1
ARETURN

L2 LOCALVARIABLE $ this Lcom / takharsh / ecdh / MainActivity; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1

Kotlin erstellt eine zusätzliche lokale Variable derselben Instanz und prüft, ob sie null ist oder nicht. Wenn null, wird 'throwUninitializedPropertyAccessException' ausgelöst. Andernfalls wird das lokale Objekt zurückgegeben. Oberhalb Bytecode erklärt hier Lösung Da Kotlin 1.2 es Wetter lateinit var initialisiert prüfen können , wurde oder nicht verwenden.isInitialized

Takharsh
quelle