skip to content

lateinit var

lateinit var covers properties that are genuinely assigned before use but not at construction — injected dependencies, @BeforeEach fixtures. The constraints matter in interviews: no val, no primitive types, and an UninitializedPropertyAccessException if you read too early.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What is `lateinit var` in Kotlin, and what problem does it solve?

level: juniorimportance: must knowfreq 80%

answer

  1. Deferred init for non-null var
  2. Avoids nullable + ?./!!
  3. DI, @BeforeEach, onCreate
  4. Throws UninitializedPropertyAccessException
  5. Skips compile-time init check

basics

~10 s

lateinit lets you declare a non-null property without giving it a value right away. You promise to set it later before using it, so you avoid making it nullable.

solid answer

~30 s

`lateinit var` marks a non-null, mutable property whose initialization is deferred to after the constructor runs. Without it, a non-null property must be assigned in the constructor or at declaration; the alternative is making it nullable (`T?`) and littering code with `?.`/`!!`. It is meant for cases where a framework assigns the value later — dependency injection (`@Autowired`, `@Inject`), JUnit `@BeforeEach` setup fields, or Android `onCreate`. The compiler skips its usual must-be-initialized check, and instead inserts a runtime guard: accessing the property before assignment throws `UninitializedPropertyAccessException`. So you trade a compile-time guarantee for cleaner non-null typing plus a clear runtime failure.

code

kotlin · 12 lines
kotlin
class Greeter {
    lateinit var name: String          // non-null, set later

    fun configure(n: String) { name = n }

    fun greet() = "Hello, $name"        // no ?. or !! needed
}

val g = Greeter()
// g.greet()        // would throw UninitializedPropertyAccessException
g.configure("Ada")
println(g.greet())  // Hello, Ada

go deeper

for a junior

Can state lateinit defers initialization of a non-null var and is set later by a framework or setup code.

for a middle

Explains the alternative (nullable + ?./!!), names DI and @BeforeEach use cases, and knows early access throws UninitializedPropertyAccessException.

for a senior

Frames it as trading a compile-time definite-assignment guarantee for clean non-null typing plus a clear runtime guard, and enumerates the restrictions.

for a principal

Discusses team conventions for when lateinit is acceptable vs constructor injection, and the maintainability trade-off of moving a guarantee to runtime.

## What `lateinit var` is `lateinit` is a modifier on a `var` property declaration. It tells the compiler: "this property is non-null, but I will not initialize it at the declaration site or in the constructor — I will assign it later, before any read." Normally Kotlin enforces *definite assignment*: a non-null property (`var name: String`) must have a value by the time the constructor finishes. `lateinit` opts out of that compile-time check. ```kotlin class UserService { lateinit var repository: UserRepository // no initializer needed fun init(repo: UserRepository) { repository = repo // assigned later } fun load(id: Long) = repository.find(id) // used as a plain non-null type } ``` ## The problem it solves Without `lateinit`, your two options are: - Initialize in the constructor — impossible when a framework supplies the value afterwards. - Make it nullable: `var repository: UserRepository? = null`. Then every use needs `?.` (safe call), `!!` (not-null assertion), or a null check, even though logically the value is always present after setup. `lateinit` keeps the **non-null type** (no `?`) so call sites stay clean, while moving the "is it set?" responsibility to runtime. ## Runtime behavior The compiler backs a `lateinit` property with a field that starts as `null` (internally) and inserts a check on every read. Reading it before assignment throws: ``` kotlin.UninitializedPropertyAccessException: lateinit property repository has not been initialized ``` This is a clear, specific failure — unlike a generic `NullPointerException`. ## Typical use sites - **Dependency injection**: Spring `@Autowired`, Jakarta `@Inject`, Dagger field injection set the field after construction. - **Test fixtures**: a field set in a JUnit 5 `@BeforeEach` method. - **Android**: `View`s or bindings assigned in `onCreate`/`onViewCreated`. ## Key restrictions (named here, detailed elsewhere) - Must be `var`, not `val`. - Cannot be a primitive type like `Int`, `Long`, `Double`, `Boolean`. - Cannot be nullable, must have no custom getter/setter, and works on top-level/member/local properties (not constructor parameters). You can check assignment with `::repository.isInitialized` (covered separately).

  • Why use `lateinit` instead of just initializing to a default like an empty string?
    A default masks the 'not configured yet' state — code silently uses the placeholder. `lateinit` makes premature access fail loudly, surfacing setup bugs instead of hiding them.
  • Does `lateinit` make the property nullable?
    No. The declared type stays non-null (e.g., `String`, not `String?`). Internally the field may hold null before assignment, but you cannot assign null to it from Kotlin.

Like reserving a seat with a name tag but no person yet — the seat is 'for a real guest' (non-null), and if someone tries to talk to the empty chair early, you get a clear 'nobody's here yet' error.

saying these in an interview costs you the question

  • Saying lateinit can be used on `val`
  • Claiming it makes the type nullable
  • Thinking early access returns null instead of throwing
  • Confusing it with `by lazy`
  • Saying it works on primitive Int/Boolean

context

open as a page

What are the restrictions on what kinds of properties can be declared `lateinit`?

level: middleimportance: must knowfreq 70%

basics

~10 s

It must be a var, not a val. It can't be a nullable type, can't be a primitive like Int or Boolean, and can't have a custom getter or setter.

open as a page

What happens if you read a `lateinit var` before it is assigned, and what exception is thrown?

level: middleimportance: must knowfreq 65%

basics

~10 s

Reading it before you set it throws an error called UninitializedPropertyAccessException. The message tells you which property wasn't initialized.

open as a page

When would you choose `lateinit var` versus `by lazy`, and what are the key differences?

level: seniorimportance: should knowfreq 60%

basics

~10 s

Use by lazy for a val you compute yourself on first read. Use lateinit var for a non-null var that something else sets later, like dependency injection or test setup.

open as a page

Critique `lateinit var` for dependency injection: what are the design and safety trade-offs versus constructor injection?

level: principalimportance: nice to knowfreq 40%

basics

~10 s

lateinit for injection is convenient but moves the 'is it set?' guarantee from compile time to runtime. Constructor injection keeps dependencies non-null and verified at construction, which is safer and easier to test.

open as a page