42

I am confuse for lateinit and nullable variable, which one to use for variable.

lateinit var c: String
var d: String? = null
c = "UserDefinedTarget"

// if not added initialisation for c than throws UninitializedPropertyAccessException
if (c == "UserDefinedTarget") {
    //do some stuff.
}
//not throws any exception whether d is initialise or not.
if(d == "UserDefinedTarget") {
     //do some stuff
}
Ilya
  • 21,871
  • 8
  • 73
  • 92
paril
  • 1,850
  • 2
  • 14
  • 26

4 Answers4

34

A type that is nullable is just that, a thing that has a valid state that is null.

A non-nullable late init var represents something where null is an invalid state, but for some reason you can't populate it in the constructor.

Android Activities are a good example of a use of lateinit. Activities must have a no args constructor and their lifecycle only really starts with onCreate().

alex
  • 6,359
  • 1
  • 23
  • 21
25

These are two completely different concepts.

You can use lateinit to avoid null checks when referencing the property. It's very convenient in case your properties are initialized through dependency injection, or, for example, in the setup method of a unit test.

However, you should keep in mind that accessing a lateinit property before it has been initialized throws an exception. That means you should use them only if you are absolutely sure, they will be initialized.

Nullable types, on the other hand, are used when a variable can hold null.


class A {
    lateinit var a: String

    fun cat() {
        print(a.length)  // UninitializedPropertyAccessException is thrown
        a = "cat"
        print(a.length)  // >>> 3
    }
}

class B {
    var b: String? = null

    fun dog() {
        print(b.length)  // won't compile, null check is obligatory here
        print(b?.length) // >>> null
        b = "dog"
        print(b?.length) // >>> 3
    }
}

For more information:

Alex Romanov
  • 11,453
  • 6
  • 48
  • 51
12

It depends. Nullable variable means that variable can hold value or null. lateinit means that variable must be initialised later. It should be initialized before accessing it. If you attempt accessing uninitialized lateinit variable UninitializedPropertyAccessException will be thrown.

It's always better to avoid using nulls in your app. Nulls are evil. So if you can initialize variable in onCreate then it's better to use lateinit. Also if you use dependency injection in your app and fields should be injected it's also a valid case to use lateinit instead of handling nulls.

If for some reason you can't initialize variable, initializing code can result to null, or null can be assigned to this variable later than you should use nullable variable. Generally speaking if null is a valid value for the variable.

Vadims Savjolovs
  • 2,618
  • 1
  • 26
  • 51
4

Use lateinit for properties that cannot be initialized in a constructor.

Gulzar Bhat
  • 1,255
  • 11
  • 13
  • Don't you mean usse `lateinit` for properties that can be initialized in the constructor. If you use lateinit and don't initialize it a constructor then you run the risk of accessing it before its been initialized resulting in a exception. – ant2009 Jul 20 '19 at 15:25
  • 1
    @ant2009 If you were to initialize it in the constructor, then the property is - by definition - not `lateinit`. Should you initialize a `lateinit` property in the constructor, the Kotlin compiler emits a `UNNECESSARY_LATEINIT` warning. – TheKvist Jul 10 '20 at 09:07
  • 1
    @TheKvist Thanks for pointing that out. if the lateinit property is initialized in a constructor its always guarenteed to be iniitialized as the constructor will always run. However, if you have a lateinit property and its not initialized in the constructor but in another method you can always check if its been initialized or not by using this `if(::fullName.isInitialized()) { /* do something */ }` This is what I normally do. – ant2009 Jul 10 '20 at 09:38
  • @ant2009 To use the `isInitialized` is how you should do it :) Just realized your original comment is over a year old, so sorry for necroing, and thanks for replying! The thing is, if you can guarantee that you will initialize the property in the constructor, there is no reason for the property to be marked as `lateinit` as it will never be "initialized later", hence the compiler warning. Personally, in classes where I have lateinit props, I define a simple `validate` method that checks itself for the lateinits to be initialized and throws an exception if they're not. – TheKvist Jul 10 '20 at 15:04