¿Cómo verificar si se ha inicializado una variable "lateinit"?

428

Me pregunto si hay una manera de verificar si una lateinitvariable se ha inicializado. Por ejemplo:

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
fuente
3
¿Quizás lo que necesita es hacer que la propiedad sea anulable (cambie el tipo a File?) y simplemente verifique si es nula?
Marcin Koziński
1
Bueno, en realidad lo intenté y funcionará, sin embargo, tendré que editar la allSeriesvar seriesDir?.listFiles()?.map { it.name }?.toTypedArray(), que no es muy "bonita"
Mathew Hany
1
Puede hacer una simple verificación nula y el reparto inteligente lo hará más bonito. if (seriesDir != null) { allSeries = seriesDir.listFiles().map { it.name }.toTypedArray() }
Marcin Koziński
Por favor considerar la aceptación de más hasta la fecha respuesta
misántropo

Respuestas:

978

Hay una lateinitmejora en Kotlin 1.2 que permite verificar el estado de inicialización de la lateinitvariable directamente:

lateinit var file: File    

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

Vea el anuncio en el blog de JetBrains o la propuesta KEEP .

ACTUALIZACIÓN: Kotlin 1.2 ha sido lanzado. Puedes encontrar lateinitmejoras aquí:

xsveda
fuente
3
@ fer.marino: Bueno, Kotlin 1.2 en realidad le permite usar lateinittambién para variables locales, consulte kotlinlang.org/docs/reference/…
xsveda el
99
this :: lateinitVar.isInitialized
vihkat
17
¿Qué significa ::antes file?
Malwinder Singh
55
@MalwinderSingh crea una referencia de miembro o una referencia de clase.
notGeek
55
Enamorado de Kotlin ahora
Naveed Ahmad
46

Usando la .isInitializedpropiedad uno puede verificar el estado de inicialización de una variable lateinit.

if(::file.isInitialized){
    //File is initialized
}else{
    //File is not initialized
}
Nikhil Katekhaye
fuente
Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar una aclaración de un autor, deje un comentario debajo de su publicación. - De la opinión
gforce301
2
@ gforce301 Definitivamente se usará para verificar.
Nikhil Katekhaye
39

Intente usarlo y recibirá un mensaje UninitializedPropertyAccessExceptionsi no está inicializado.

lateinites específicamente para casos donde los campos se inicializan después de la construcción, pero antes del uso real (un modelo que utilizan la mayoría de los marcos de inyección). Si este no es su caso de uso, lateinitpodría no ser la elección correcta.

EDITAR: según lo que quieras hacer, algo como esto funcionaría mejor:

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

// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())
Kiskae
fuente
Tengo una aplicación JavaFX y tengo un botón que siempre se desactivará a menos que se lateinithaya inicializado una variable (que es ). En otras palabras: quiero que el botón esté deshabilitado siempre que la variable no se haya inicializado. ¿Hay una buena manera de hacer eso?
Mathew Hany
@MathewHany ¿Cómo se inicializaría normalmente? Es posible que desee ver los captadores / establecedores de propiedades y una propiedad SimpleBooleanProperty que puede vincular a la propiedad deshabilitada del botón
Kiskae
1
Para ser más específico, tengo una aplicación simple que contiene 4 botones, el primer botón abrirá un cuadro de diálogo DirectoryChooser y los otros 3 se deshabilitarán, cuando el usuario elija un directorio, todos los demás botones estarán disponibles para el usuario.
Mathew Hany
@MathewHany puedes implementarlo de forma nativa usando SimpleObjectProperty para guardar el archivo elegido, luego usando el isNull enlace para deshabilitar los otros botones.
Kiskae
1
kotlinlang.org/docs/reference/… La respuesta de xsveda está más actualizada
Serge
19

Puedes hacer esto fácilmente:

::variableName.isInitialized

o

this::variableName.isInitialized

Pero si estás dentro de un oyente o una clase interna, haz esto:

this@YourClassName::variableName.isInitialized

Nota: Las declaraciones anteriores funcionan bien si las escribe en el mismo archivo (misma clase o clase interna) donde se declara la variable, pero esto no funcionará si desea verificar la variable de otra clase (no la superclase o declarada en otro archivo) , por ejemplo:

class Test {
    lateinit var str:String
}

Y para verificar si str está inicializado:

ingrese la descripción de la imagen aquí

Lo que estamos haciendo accediendo al campo strde Testclase en Test2clase. Y obtenemos un error al respaldar el campo de var no es accesible en este momento. Revisa una pregunta ya planteada sobre esto.

Suraj Vaishnav
fuente
12

La respuesta aceptada me da un error de compilación Kotlin 1.3+, tuve que mencionar explícitamente la thispalabra clave antes ::. A continuación se muestra el código de trabajo.

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}
Sazzad Hissain Khan
fuente
Estoy usando una variable de inicio local cuando uso esta verificación que da un error como referencia no resuelta
MarGin
3

Para verificar si lateinit varse inicializó o no, utilice a .isInitializeden la referencia a esa propiedad:

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

Esta comprobación solo está disponible para las propiedades que son accesibles léxicamente, es decir, declaradas en el mismo tipo o en uno de los tipos externos, o en el nivel superior en el mismo archivo.

Andy
fuente
1
¿Qué significa ::antes bar?
Malwinder Singh
@Malwinder Singh "crea una referencia de miembro o una referencia de clase" - Kotlin Doc
DMonkey
0
kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized

Bytecode dice ... 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 crea una variable local adicional de la misma instancia y comprueba si es nula o no, si es nula, arroja 'throwUninitializedPropertyAccessException' o devuelve el objeto local. Por encima del código de bytes explicado aquí Solución Desde kotlin 1.2 permite verificar el clima lateinit var se ha inicializado o no utiliza.isInitialized

takharsh
fuente