Что такое делегат lazy в Kotlin
Что проверяют
Понимаете ли вы механику делегированных свойств и осознанно ли выбираете между lazy, lateinit и обычной инициализацией. В Android к этому добавляется жизненный цикл: именно на нём lazy чаще всего и подводит.
Как отвечать
Запись val с делегатом lazy создаёт объект Lazy. При первом чтении выполняется блок, результат запоминается, все следующие обращения возвращают то же значение. Работает только с val, потому что значение по определению одно.
Режим по умолчанию синхронизированный: блокировка с двойной проверкой, безопасно при обращении из разных потоков. Режим публикации допускает параллельный расчёт, но закрепляет первый результат. Режим без синхронизации подходит, когда свойство читается только с главного потока, что в интерфейсном коде типично.
class DetailActivity : AppCompatActivity() {
private val itemId by lazy(LazyThreadSafetyMode.NONE) {
intent.getStringExtra("item_id").orEmpty()
}
}Сравнение просят почти всегда: lateinit нужен для var, значение задаётся снаружи (внедрение зависимостей, onCreate), с примитивами он не работает и ничего не кэширует, а обычный val вычисляется в конструкторе, даже если не понадобится.
Где спотыкаются
Кладут в lazy то, что живёт короче объекта. Ссылка на разметку во фрагменте вычисляется один раз, а представление фрагмента пересоздаётся при возврате по стеку: свойство продолжает указывать на старую иерархию, обновления не видны, память удерживается.
Считают lazy бесплатным. Это лишний объект на каждое свойство и синхронизация на каждом чтении в режиме по умолчанию. Для дешёвого значения обычная инициализация выходит быстрее и проще.
Ждут, что исключение из блока запомнится. Оно просто пробрасывается наружу, свойство остаётся неинициализированным, и следующее обращение снова запустит блок со всеми побочными действиями внутри.