lateinit var vs. val by lazy in Android

Tests your grasp of Kotlin property initialization and its lifecycle implications. A good answer contrasts mutability (var/val), initialization timing, and thread safety.
WHAT THIS TESTS: This question probes your understanding of Kotlin's mechanisms for deferring property initialization. It's not just about syntax; it's about knowing the performance, safety, and lifecycle trade-offs of each approach, especially within the constraints of the Android framework where objects are created at specific times (like in onCreate). The interviewer is looking for evidence that you can choose the right tool for the job to write clean, safe, and efficient code.
A GOOD ANSWER COVERS: A great answer will contrast the two along four key axes. First, mutability: lateinit must be a var, while lazy properties are val. Second, initialization: lateinit is initialized manually by you at some point before its first use, whereas lazy is initialized automatically on its first access. Third, type constraints: lateinit is for non-nullable reference types that can't be initialized in the constructor and cannot be used for primitive types like Int or Boolean. Fourth, thread safety: lazy is thread-safe by default (using SYNCHRONIZED mode), ensuring the initializer is called only once, while you must manually manage thread safety for lateinit properties if accessed from multiple threads.
COMMON WRONG ANSWERS: A red flag is treating them as interchangeable. Candidates often forget that lateinit cannot be used on primitive types. A major mistake is failing to mention the runtime risk of lateinit: accessing it before initialization throws an UninitializedPropertyAccessException. Conversely, some candidates forget the slight overhead of the lazy delegate, which involves a lock for thread safety (by default) and an extra object allocation for the delegate itself. Simply saying one is for var and one is for val is a junior-level answer.
LIKELY FOLLOW-UPS: An interviewer might ask, "How can you change the thread-safety mode of by lazy and why would you?" (Answer: Use LazyThreadSafetyMode.PUBLICATION or LazyThreadSafetyMode.NONE for performance gains when you can guarantee single-threaded access, like on the Android main thread). Another follow-up could be, "How would you check if a lateinit var has been initialized?" (Answer: Use this::myVar.isInitialized before accessing it, available since Kotlin 1.2).
ONE CONCRETE EXAMPLE: For lateinit, a classic Android use case is for a View Binding object or a RecyclerView adapter in an Activity or Fragment: private lateinit var binding: ActivityMainBinding. You are guaranteed to initialize it in onCreate after setContentView, so lateinit avoids making it nullable. For by lazy, it's perfect for expensive, read-only objects that might not be needed, like a complex helper class or a database instance: private val userProfileViewModel: UserProfileViewModel by viewModels(). This ensures the ViewModel is only created if and when it's actually used, saving resources.
Read the original → kotlinlang.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.