Question
In Kotlin, how can you check whether a lateinit property has already been initialized before using it?
For example:
class Foo {
private lateinit var myFile: File
fun bar(path: String?) {
path?.let { myFile = File(it) }
}
fun bar2() {
myFile.whateverMethod()
// This may crash if myFile has not been initialized yet
}
}
I want to know whether there is a safe way to detect if myFile has been initialized before accessing it.
Short Answer
By the end of this page, you will understand what Kotlin lateinit properties are, how to check whether they have been initialized, when that check is useful, and what alternatives like nullable properties or lazy delegation may be better in some situations.
Concept
lateinit in Kotlin lets you declare a non-null var without assigning a value immediately.
lateinit var name: String
This is useful when a value cannot be created at object construction time, but you promise it will be assigned before use.
However, if you access a lateinit property before assigning it, Kotlin throws an UninitializedPropertyAccessException.
That is exactly the risk in this example:
private lateinit var myFile: File
If bar2() runs before bar() assigns myFile, the program can crash.
Kotlin provides a built-in way to check whether a lateinit property is initialized:
this::myFile.isInitialized
This uses a property reference. It asks Kotlin for metadata about the property and returns true if the property has already received a value.
Mental Model
Think of a lateinit property like a locker with a label on it, but nothing has been placed inside yet.
- Declaring the locker means the space exists
- Initializing it means putting the item inside
- Accessing it before putting anything inside causes an error
isInitializedis like checking whether the locker already contains something
So instead of blindly opening the locker and expecting an item, you first check whether it has been filled.
Syntax and Examples
The basic syntax for checking a lateinit property is:
if (this::myProperty.isInitialized) {
// safe to use myProperty
}
Example with your case
import java.io.File
class Foo {
private lateinit var myFile: File
fun bar(path: String?) {
path?.let { myFile = File(it) }
}
fun bar2() {
if (this::myFile.isInitialized) {
println(myFile.path)
} else {
println("myFile is not initialized yet")
}
}
}
What this does
this::myFilecreates a reference to the property.isInitializedchecks whether thelateinitvariable has been assigned- If it has, you can use
myFile - If not, you handle that case safely
Step by Step Execution
Consider this example:
import java.io.File
class Foo {
private lateinit var myFile: File
fun setFile(path: String?) {
path?.let { myFile = File(it) }
}
fun printFilePath() {
if (this::myFile.isInitialized) {
println(myFile.path)
} else {
println("No file has been set")
}
}
}
Now trace it step by step.
Case 1: property not initialized
val foo = Foo()
foo.printFilePath()
Execution:
Foo()creates an objectmyFileexists as alateinitproperty, but no value has been assigned yetprintFilePath()runsthis::myFile.isInitializedreturnsfalse
Real World Use Cases
lateinit initialization checks appear in situations where setup happens later than object creation.
Android and UI lifecycle
A view or binding object may be assigned in a lifecycle method and accessed later.
if (this::binding.isInitialized) {
binding.textView.text = "Ready"
}
Dependency injection
A dependency may be injected after construction.
lateinit var repository: UserRepository
Before using it in some special flow, you might verify it has been assigned.
Test setup
In unit tests, objects are often initialized in @Before methods.
lateinit var service: UserService
A check can help in utility methods if setup is conditional.
Delayed resource creation
A file, socket, parser, or cache object might only be created if configuration is valid.
path?.let { myFile = File(it) }
Then later code can safely check whether setup succeeded.
Optional component wiring
Real Codebase Usage
In real projects, developers usually use lateinit carefully and combine it with clear control flow.
Common pattern: guard clause
fun processFile() {
if (!this::myFile.isInitialized) return
println(myFile.path)
}
This is simple and avoids deeply nested if statements.
Common pattern: fail fast with a clear message
fun processFile() {
check(this::myFile.isInitialized) { "myFile must be initialized before calling processFile()" }
println(myFile.path)
}
This is useful when missing initialization is a programmer error, not a normal runtime case.
Common pattern: initialize in one place
Instead of checking everywhere, many codebases centralize setup.
fun initialize(path: String) {
myFile = File(path)
}
Then other methods assume initialization has already happened.
Common pattern: prefer nullable when absence is valid
Common Mistakes
1. Accessing a lateinit property without checking
Broken code:
fun bar2() {
println(myFile.path)
}
Problem:
- This crashes if
myFilewas never assigned
Fix:
fun bar2() {
if (this::myFile.isInitialized) {
println(myFile.path)
}
}
2. Using lateinit when null is a valid state
Broken design:
private lateinit var selectedFile: File
Problem:
- If "no file selected yet" is a normal state,
lateinithides that fact
Better:
private var selectedFile: File? =
Comparisons
| Concept | What it means | Best when | Main drawback |
|---|---|---|---|
lateinit var x: Type | Non-null property assigned later | You guarantee assignment before use | Can crash if accessed too early |
var x: Type? = null | Nullable property | Missing value is a normal state | Requires null handling |
val x by lazy { ... } | Value created on first access | Value can be computed automatically once | Read-only and not manually reassigned |
| Constructor parameter | Value required at creation time | Object should never exist without it | Less flexible for delayed setup |
lateinit vs nullable
Cheat Sheet
lateinit var name: String
Check initialization:
if (this::name.isInitialized) {
println(name)
}
Guard clause pattern:
if (!this::name.isInitialized) return
Fail-fast pattern:
check(this::name.isInitialized) { "name must be initialized" }
Rules:
lateinitworks only withvar- property must be non-null
- not allowed for primitive types like
IntorBoolean - accessing before initialization throws
UninitializedPropertyAccessException isInitializedworks only forlateinitproperties
Prefer nullable instead when missing data is normal:
FAQ
How do I check if a lateinit variable is initialized in Kotlin?
Use a property reference with isInitialized:
if (this::myFile.isInitialized) {
// use myFile
}
What happens if I access a lateinit property before initialization?
Kotlin throws an UninitializedPropertyAccessException at runtime.
Can I use lateinit with val?
No. lateinit only works with mutable properties declared using var.
Can I use lateinit with Int or other primitive types?
No. lateinit is not allowed for primitive types.
Should I use lateinit or a nullable property?
Use lateinit when the value should never logically be null but is assigned later. Use a nullable property when absence is a normal state.
Mini Project
Description
Build a small Kotlin class that manages a log file path. The file should only be created when a valid path is provided, and another method should safely print file information only if the lateinit property has been initialized. This demonstrates delayed initialization and safe access in a realistic way.
Goal
Create a class that safely uses a lateinit File property without crashing when the file has not been set yet.
Requirements
- Create a class with a
lateinitproperty of typeFile - Add a method that initializes the file only when the path is not null or blank
- Add a method that checks whether the property is initialized before using it
- Print a clear message when the file is not available yet
Keep learning
Related questions
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.
Can You Extend a Data Class in Kotlin? Inheritance, Limits, and Better Alternatives
Learn why Kotlin data classes cannot be extended, what causes the component function clash, and which alternatives to use instead.
Difference Between List and Array in Kotlin
Learn the difference between List and Array in Kotlin, including mutability, size, APIs, performance, and when to use each one.