Como verificar se uma variável "lateinit" foi inicializada?

428

Gostaria de saber se existe uma maneira de verificar se uma lateinitvariável foi inicializada. Por exemplo:

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
fonte
3
Talvez o que você precise é tornar a propriedade anulável (altere o tipo para File?) e verifique se ela é nula?
Marcin Koziński
1
Bem, eu realmente tentei isso e ele vai fazer o truque, no entanto eu vou ter que editar o allSeriesvar para seriesDir?.listFiles()?.map { it.name }?.toTypedArray(), o que não é muito "bonito"
Mathew Hany
1
Você pode fazer uma verificação nula simples e antiga e a conversão inteligente a tornará mais bonita. if (seriesDir != null) { allSeries = seriesDir.listFiles().map { it.name }.toTypedArray() }
Marcin Koziński
Por favor, considere aceitar mais atualizado resposta
misantropo

Respostas:

978

Há uma lateinitmelhoria no Kotlin 1.2 que permite verificar lateinitdiretamente o estado de inicialização da variável:

lateinit var file: File    

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

Veja o comunicado no blog JetBrains ou a proposta KEEP .

ATUALIZAÇÃO: Kotlin 1.2 foi lançado. Você pode encontrar lateinitmelhorias aqui:

xsveda
fonte
3
@ fer.marino: Bem, o Kotlin 1.2 realmente permite que você use lateinittambém para variáveis ​​locais, consulte kotlinlang.org/docs/reference/…
xsveda
9
Isso :: lateinitVar.isInitialized
vihkat 11/11
17
qual é o significado de ::antes file?
Malwinder Singh 16/05/19
5
@MalwinderSingh cria uma referência de membro ou uma referência de classe.
notGeek
5
No amor com Kotlin agora
Naveed Ahmad
46

Usando a .isInitializedpropriedade, é possível verificar o estado de inicialização de uma variável lateinit.

if(::file.isInitialized){
    //File is initialized
}else{
    //File is not initialized
}
Nikhil Katekhaye
fonte
Isso não fornece uma resposta para a pergunta. Para criticar ou solicitar esclarecimentos a um autor, deixe um comentário abaixo da postagem. - Do comentário
gforce301
2
@ gforce301 Definitivamente será usado para verificação.
Nikhil Katekhaye
39

Tente usá-lo e você receberá um UninitializedPropertyAccessExceptionse não for inicializado.

lateinité especificamente para casos em que os campos são inicializados após a construção, mas antes do uso real (um modelo usado pela maioria das estruturas de injeção). Se esse não for seu caso de usolateinit pode não ser a escolha certa.

EDIT: Com base no que você deseja fazer algo assim funcionaria melhor:

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

// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())
Kiskae
fonte
Eu tenho um aplicativo JavaFX e um botão que sempre será desativado, a menos que uma variável (que seja lateinit) tenha sido inicializada. Em outras palavras: desejo que o botão seja desativado enquanto a variável não tiver sido inicializada. Existe uma boa maneira de fazer isso?
Mathew Hany
@ MathewHany Como seria inicializado normalmente? Você pode querer olhar para propriedade getter / setters e uma SimpleBooleanProperty que você pode vincular a propriedade desativado do botão
Kiskae
1
Para ser mais específico, eu tenho um aplicativo simples que contém 4 botões, o primeiro botão abrirá uma caixa de diálogo DirectoryChooser e os outros 3 serão desativados quando o usuário escolher um diretório, e todos os outros botões estarão disponíveis para o usuário.
Mathew Hany
@ MathewHany, você pode implementar isso nativamente usando um SimpleObjectProperty para armazenar o arquivo escolhido e, em seguida, usando a isNullligação para desativar os outros botões.
Kiskae
1
kotlinlang.org/docs/reference/... xsveda resposta é mais atualizado
Serge
19

Você pode fazer isso facilmente:

::variableName.isInitialized

ou

this::variableName.isInitialized

Mas se você estiver dentro de um ouvinte ou classe interna, faça o seguinte:

this@YourClassName::variableName.isInitialized

Nota: As instruções acima funcionam bem se você as estiver gravando no mesmo arquivo (mesma classe ou classe interna) em que a variável é declarada, mas isso não funcionará se você desejar verificar a variável de outra classe (não a superclasse ou declarada em outro arquivo) , por exemplo:

class Test {
    lateinit var str:String
}

E para verificar se str é inicializado:

insira a descrição da imagem aqui

O que estamos fazendo aqui acessando o campo strde Testclasse em Test2classe. E obtemos um erro ao fazer o campo var não estar acessível neste momento. Verifique uma pergunta já levantada sobre isso.

Suraj Vaishnav
fonte
12

A resposta aceita gera um erro do compilador. Kotlin 1.3+Eu tive que mencionar explicitamente a thispalavra - chave antes ::. Abaixo está o código de trabalho.

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}
Sazzad Hissain Khan
fonte
Eu estou usando uma variável init local quando eu uso esta verificação que dá um erro como referência não resolvida
MarGin 08/01
3

Para verificar se a lateinit varfoi inicializado ou não use a .isInitializedna referência a essa propriedade:

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

Essa verificação está disponível apenas para as propriedades acessíveis lexicamente, ou seja, declaradas no mesmo tipo ou em um dos tipos externos, ou no nível superior no mesmo arquivo.

Andy
fonte
1
qual é o significado de ::antes bar?
Malwinder Singh 16/05/19
@Malwinder Singh "cria uma referência membro ou uma referência de classe" - Kotlin Doc
DMonkey
0
kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized

Bytecode diz ... blá blá ..

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

O Kotlin cria uma variável local extra da mesma instância e verifica se ela é nula ou não, se nula lança 'throwUninitializedPropertyAccessException' ou então retorna o objeto local. O bytecode acima explicado aqui Solução Como o kotlin 1.2, ele permite verificar se o lateinit var foi inicializado ou não está sendo usado.isInitialized

takharsh
fonte