What is `lateinit var` in Kotlin and what problem does it solve?
answer
- Deferred init of non-null var
- var only, non-null only, no primitives
- Avoids making type nullable
- UninitializedPropertyAccessException on early read
- DI / Android onCreate / test @BeforeEach
basics
~20 slateinit var lets you declare a non-null variable without giving it a value right away. You promise to set it before you read it. It's used when a value isn't known at object creation but will be ready before first use.
solid answer
~40 s`lateinit` is a modifier on a mutable `var` of a non-null reference type that tells the compiler you will assign it later, before any read. Without it, a non-null property must be initialized in the constructor or at declaration. It's typically used for dependency injection, framework callbacks (e.g. Android `onCreate`, JUnit `@BeforeEach`), or builder-style setup where the value isn't available at construction time. The compiler skips the null check it would normally enforce, so you avoid making the type nullable (`Type?`) just to defer assignment. If you read it before assigning, you get an `UninitializedPropertyAccessException`. You can guard with `::prop.isInitialized` to check assignment state.
code
kotlin · 11 linesclass Greeter {
lateinit var name: String
fun setup(n: String) { name = n }
fun greet() = "Hello, $name" // throws if setup() not called first
}
val g = Greeter()
// g.greet() // UninitializedPropertyAccessException
g.setup("Ada")
println(g.greet()) // Hello, Adago deeper
Knows it defers initialization of a non-null var and that you must assign before reading.
Explains why it beats a nullable type and lists the var/non-null/no-primitive constraints.
Frames it as moving the non-null guarantee from compile time to runtime and names real use cases (DI, lifecycle, tests).
Discusses design trade-offs of giving up compiler verification and when an alternative (lazy, constructor injection, nullable) is the better contract.
## What `lateinit` means Kotlin enforces null safety: a property with a non-null type (like `String`, not `String?`) must hold a value at all times. Normally that means you initialize it in the constructor or at the declaration site. But sometimes the real value isn't available yet at construction time — for example a field injected by Spring/Dagger, or a view assigned in Android's `onCreate`, or a test fixture set up in `@BeforeEach`. `lateinit` is a modifier that says: *"This non-null `var` will be assigned later, before anyone reads it — trust me, compiler."* ```kotlin class UserService { lateinit var repository: UserRepository // no value yet fun init(repo: UserRepository) { repository = repo // assigned later } fun findUser(id: Long) = repository.find(id) // safe if init() ran first } ``` ## The alternative it replaces Without `lateinit`, you'd either: - Make it nullable: `var repository: UserRepository? = null` — then every use needs `?.` or `!!`, polluting the code with null handling for something you know is non-null after setup. - Initialize with a dummy/default value — often impossible or wasteful. `lateinit` keeps the type non-null and avoids both. ## Key constraints - Only on `var` (mutable), never `val`. - Only on **non-null** types (`String`, not `String?`). - **Not** allowed on primitive types like `Int`, `Boolean`, `Double` (use `by Delegates.notNull()` instead). - No custom getter/setter. - Can be a member property, top-level property, or local variable. ## What happens on early access Reading before assignment throws `UninitializedPropertyAccessException` ("lateinit property X has not been initialized"). You can defensively check with the reference syntax `::repository.isInitialized`. ## Mental model `lateinit` is a **deferred, unchecked promise** of non-null. The benefit is clean non-null types; the cost is that the compiler can no longer guarantee initialization — that responsibility moves to you, enforced at runtime instead of compile time.
- Why not just use a nullable type instead?A nullable type forces null handling (`?.`, `!!`) on every access even though the value is logically always present after setup. `lateinit` keeps the type non-null so call sites stay clean.
- Can `lateinit` be applied to a `val`?No. `lateinit` requires a `var` because assignment happens after declaration; a `val` can only be assigned once and must be initialized at its single assignment point.
Like reserving a parking spot with your name on it before your car arrives — the slot exists and is non-null, but trying to drive away before the car shows up fails.
saying these in an interview costs you the question
- Claiming `lateinit` works on `val`
- Saying it works on primitives like `Int`
- Thinking it gives the property a default value (it doesn't)
- Confusing it with `lazy` (which auto-initializes on first read)
- Believing early access returns null instead of throwing