586

I wonder if there is a way to check if a lateinit variable has been initialized. For example:

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
    }
}
Juan José Melero Gómez
  • 2,617
  • 1
  • 16
  • 34
Mathew Hany
  • 9,598
  • 4
  • 16
  • 15
  • 3
    Maybe what you need is to make the property nullable (change type to `File?`) and just check if it is null instead? – Marcin Koziński Jun 03 '16 at 16:40
  • 1
    Well, I actually tried that and it will do the trick, however I will have to edit the `allSeries` var to `seriesDir?.listFiles()?.map { it.name }?.toTypedArray()`, which is not very "pretty" – Mathew Hany Jun 03 '16 at 20:24
  • 1
    You can do a plain old null check and smart cast will make it prettier. `if (seriesDir != null) {` `allSeries = seriesDir.listFiles().map { it.name }.toTypedArray()` `}` – Marcin Koziński Jun 03 '16 at 20:28
  • Please consider accepting more up to date [answer](https://stackoverflow.com/a/46584412/7598113) – kuza Mar 18 '19 at 07:22

9 Answers9

1280

There is a lateinit improvement in Kotlin 1.2 that allows to check the initialization state of lateinit variable directly:

lateinit var file: File    

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

See the annoucement on JetBrains blog or the KEEP proposal.

UPDATE: Kotlin 1.2 has been released. You can find lateinit enhancements here:

Michael
  • 8,464
  • 2
  • 59
  • 62
xsveda
  • 13,503
  • 2
  • 14
  • 16
  • 3
    @fer.marino: Well, Kotlin 1.2 actually allows you to use `lateinit` also for local variables, see http://kotlinlang.org/docs/reference/whatsnew12.html#lateinit-top-level-properties-and-local-variables – xsveda Nov 29 '17 at 20:59
  • This ain't working for me. I get "lateinit property has not been initialized" even after using it. – Kishan Solanki May 29 '18 at 04:13
  • 11
    this::lateinitVar.isInitialized – vihkat Oct 11 '18 at 08:31
  • 30
    what is meaning of `::` before `file`? – Malwinder Singh May 16 '19 at 05:37
  • 10
    @MalwinderSingh it creates a member reference or a class reference. – notGeek Jul 10 '19 at 16:54
  • 1
    @MalwinderSingh it creates a member reference like @notGeek mentioned. Since here we are referring to the reference within this class, the ```this``` keyword is not necessary. The verbose syntax is ```if (this::file.isInitialized) { ... }``` – Haomin Nov 05 '19 at 22:45
  • You should add a disclaimer warning that using this method is by no means the intended way to use the lateinit modifier in a pro environment. – Juan José Melero Gómez Nov 27 '19 at 11:52
  • Oh yeah, should have guessed that we need two colons in a row. Monkeys typing could have figured that out in a few hundred years. And it's soooo more intuitive and easier to type than `if (file == null)`. I'm glad kotlin saves us so much typing and is so easy to understand! – SMBiggs Aug 31 '20 at 22:21
  • 2
    How do we check this for local `lateinit`, where `this` is something different? – Abhijit Sarkar Sep 25 '20 at 06:30
  • It seems that this can be done from inside the class, but I can't find any source. – Minh Nghĩa Dec 17 '20 at 17:04
  • Abhijit Sarkar "this" in "this::file path.isInitialized() references a fragment or activity... So if let's say you need to call it inside of a coroutine , you can make a variable to reference your fragment like - val fragment = MyFragment() and then do "fragment::filePath.isInitialized() ".... Or if "this" references a context (which it usually does), you can use "requireContext() " instead of "this". – Cosovic May 19 '21 at 22:28
  • using `isInitialized` is a code smell. Only use case I see is in a transition/migration phase when converting Java code to Kotlin or maybe some library code that doesn't want to expose nullable values. All other cases should use nullable values. That's what they're for. – Nilzor May 25 '21 at 18:23
82

Using .isInitialized property one can check initialization state of a lateinit variable.

if (::file.isInitialized) {
    // File is initialized
} else {
    // File is not initialized
}
Willi Mentzel
  • 21,499
  • 16
  • 88
  • 101
Nikhil Katekhaye
  • 1,197
  • 10
  • 17
51

You can easily do this by:

::variableName.isInitialized

or

this::variableName.isInitialized

But if you are inside a listener or inner class, do this:

this@OuterClassName::variableName.isInitialized

Note: The above statements work fine if you are writing them in the same file(same class or inner class) where the variable is declared but this will not work if you want to check the variable of other class (which could be a superclass or any other class which is instantiated), for ex:

class Test {
    lateinit var str:String
}

And to check if str is initialized:

enter image description here

What we are doing here: checking isInitialized for field str of Test class in Test2 class. And we get an error backing field of var is not accessible at this point. Check a question already raised about this.

Suraj Vaishnav
  • 5,731
  • 3
  • 29
  • 40
41

Try to use it and you will receive a UninitializedPropertyAccessException if it is not initialized.

lateinit is specifically for cases where fields are initialized after construction, but before actual use (a model which most injection frameworks use). If this is not your use case lateinit might not be the right choice.

EDIT: Based on what you want to do something like this would work better:

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

// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())
Gastón Saillén
  • 9,076
  • 4
  • 39
  • 58
Kiskae
  • 20,686
  • 1
  • 58
  • 60
  • I have a JavaFX application, and I have a button which will be always disables unless a variable (which is `lateinit`) has been initialized. In other words: I want the button to be disabled as long as the variable hasn't been initialized. Is there a good way to do that? – Mathew Hany Jun 03 '16 at 16:04
  • @MathewHany How would it be getting initialized normally? You might want to look at property getter/setters and a SimpleBooleanProperty which you can bind to the disabled property of the button – Kiskae Jun 03 '16 at 16:06
  • 1
    To be more specific, I have a simple app that contains 4 buttons, the first button will open a DirectoryChooser dialog, and the other 3 will be disabled, when the user choose a directory then all the other buttons will be available to the user. – Mathew Hany Jun 03 '16 at 16:07
  • @MathewHany you can natively implement that using a SimpleObjectProperty to hold the chosen file, then using the `isNull` binding to disable the other buttons. – Kiskae Jun 03 '16 at 18:06
  • 1
    https://kotlinlang.org/docs/reference/whatsnew12.html#checking-whether-a-lateinit-var-is-initialized xsveda answer is more up to date – MainActivity Aug 13 '18 at 10:50
  • @Serge True, although for this specific question `lateinit` was not really the correct solution anyway – Kiskae Aug 13 '18 at 15:26
15

Accepted answer gives me a compiler error in Kotlin 1.3+, I had to explicitly mention the this keyword before ::. Below is the working code.

lateinit var file: File

if (this::file.isInitialized) {

    // file is not null
}
Sazzad Hissain Khan
  • 29,428
  • 20
  • 134
  • 192
  • I am using a local init variable when I use this check that gives an error like unresolved reference – MarGin Jan 08 '20 at 09:35
9

If you have a lateinit property in one class and need to check if it is initialized from another class

if(foo::file.isInitialized) // this wouldn't work

The workaround I have found is to create a function to check if the property is initialized and then you can call that function from any other class.

Example:

class Foo() {

    private lateinit var myFile: File

    fun isFileInitialised() = ::file.isInitialized
}

 // in another class
class Bar() {

    val foo = Foo()

    if(foo.isFileInitialised()) // this should work
}
Willi Mentzel
  • 21,499
  • 16
  • 88
  • 101
Max
  • 12,408
  • 4
  • 48
  • 62
4

To check if a lateinit var were initialised or not use a .isInitialized on the reference to that property:

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

This checking is only available for the properties that are accessible lexically, i.e. declared in the same type or in one of the outer types, or at top level in the same file.

Andy Fedoroff
  • 26,838
  • 8
  • 85
  • 144
2

For me It worked

if (::file.isInitialized) {
 //true
} 
else {
//false
}
Aalishan Ansari
  • 313
  • 1
  • 4
1
kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized

Bytecode says...blah blah..

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 creates an extra local variable of same instance and check if it null or not, if null then throws 'throwUninitializedPropertyAccessException' else return the local object. Above bytecode explained here Solution Since kotlin 1.2 it allows to check weather lateinit var has been initialized or not using .isInitialized

takharsh
  • 1,008
  • 9
  • 18