DEV Community

Cover image for Kotlin lazy vs lateinit: When and Why You Should Use Them
Nyerhovwo Adjekughene (Nero)
Nyerhovwo Adjekughene (Nero)

Posted on

Kotlin lazy vs lateinit: When and Why You Should Use Them

Knowing when to use lazy or lateinit is one of those "aha" moments that separates clean, reliable Kotlin code from spaghetti code - especially in Android development. In this post, I'll break down these powerful property delegates, share my Android use cases, and help you decide which one is right - and when.


🧐 So, what are they?
Both lazy and lateinit are tools that allow delayed initialization of properties - but they solve different problems.
Think of it like this:
🛋️ lazy is like setting up a beanbag you'll only sit on when you feel like it
🔧 lateinit is like screwing on a table leg after you've assembled the frame


Kotlin lazy – For Read-Only, One-Time Initialization
lazy lets you define a read-only property (val) whose value is computed only once - the first time it's accessed.

Real Example: Lazy-loading a Retrofit service

val apiService by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .build()
        .create(ApiService::class.java)
}
Enter fullscreen mode Exit fullscreen mode

Why this works great:
We only initialize the Retrofit service when needed
Saves memory during early startup
Keeps it thread-safe by default (SYNCHRONIZED mode)

🧪 Another Example: Config loading

val config by lazy(LazyThreadSafetyMode.NONE) {
    loadRemoteConfig()
}
Enter fullscreen mode Exit fullscreen mode

This disables synchronization for better performance if you guarantee no race conditions (like using it in onCreate() only).


Kotlin lateinit – For Mutable Properties Set Later
lateinit is your tool when you want to declare a non-null var that will be initialized after the object is constructed.

✅ Common in Android:

private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)
}
Enter fullscreen mode Exit fullscreen mode

Here, you can't initialize binding at the point of declaration, because layoutInflater isn't ready yet.


⚔️ *lazy vs lateinit *– When to Use Each
Ask Yourself Use Is it a val, and only needs 1 init? lazy Is it a var, assigned after init? lateinit Is it null-safe and side-effect-free? lazy Do you need dependency injection later? lateinit


🧨 Common Mistakes to Avoid
❌ Accessing lateinit before it's initialized

if (::someVar.isInitialized) {
    println(someVar)
}
Enter fullscreen mode Exit fullscreen mode

Always check with ::yourVar.isInitialized to avoid UninitializedPropertyAccessException.


Real-world Android Dev Examples
💡 Lazy ViewModel Factory

val viewModelFactory by lazy {
    MyCustomViewModelFactory(requireContext())
}
Enter fullscreen mode Exit fullscreen mode

Useful when building custom ViewModels in Fragments or Composables.


lateinit + Dependency Injection (e.g. Dagger/Hilt)

@Inject
lateinit var userRepo: UserRepository
Enter fullscreen mode Exit fullscreen mode

You can't use constructor injection in some Android components (like Fragments), so lateinit is perfect here.


Why This Matters in Real Apps
In one of my projects, using lazy helped me avoid triggering an expensive image loading setup until the user actually opened the gallery screen - reducing cold startup time.
In another case, lateinit saved me from null checks all over a test suite where I needed to inject mocked APIs.
The more your Android app grows, the more these tools help keep code clean, readable, and maintainable.


🧑‍🏫 Final Advice
🧘 Use lazy when you're dealing with one-time expensive operations
🔧 Use lateinit when you can't initialize immediately but want to avoid nullable types
🤝 Document or comment fields clearly - they might crash if accessed too early!


🤝** Let's Connect**
If you found this article useful or want to ask me about anything from Kotlin to Clean Architecture:

LinkedIn: Here
GitHub: Here (www.github.com/nerojust)

AndroidDev #Kotlin #Coroutines #MobileDevelopment #ModernAndroid #DevJourney #CleanArchitecture #MVVM

Top comments (0)