lateinit и отложенная инициализация
Используйте lateinit для свойств, присваиваемых позднее, а by lazy — для отложенных вычислений.
«lateinit и отложенная инициализация» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.
Два инструмента для отложенной настройки
Иногда свойство нельзя инициализировать во время создания объекта. Kotlin предоставляет lateinit для переменных var, присваиваемых позже, и by lazy для переменных val, вычисляемых при первом обращении.
Основы lateinit
lateinit var откладывает инициализацию. Переменная должна быть не-null переменной var непримитивного типа. Обращение до присваивания вызывает исключение UninitializedPropertyAccessException.
class Service {
lateinit var name: String
fun init(value: String) { name = value }
}
fun main() {
val s = Service()
s.init("MyService")
println(s.name)
}Зачем использовать lateinit
Используйте lateinit для внедрения зависимостей, тестовых данных или управляемых фреймворком жизненных циклов, например представлений Android и компонентов Spring, когда инициализация происходит за пределами конструктора.
class Repository {
lateinit var db: String // assigned later by DI framework
fun query() = "querying $db"
}
fun main() {
val r = Repository()
r.db = "postgres://localhost"
println(r.query())
}Проверка isInitialized
Проверить, было ли присвоено значение свойству lateinit, можно с помощью ::propName.isInitialized.
class Foo {
lateinit var bar: String
fun status() = if (::bar.isInitialized) "set to $bar" else "unset"
}
fun main() {
val f = Foo()
println(f.status()) // unset
f.bar = "hi"
println(f.status())
}Ограничения lateinit
Нельзя использовать lateinit для примитивных типов, таких как Int и Boolean, для nullable-типов или для val. Компилятор обеспечивает соблюдение этих правил.
// VALID:
lateinit var name: String
// INVALID:
// lateinit var count: Int // primitives not allowed
// lateinit val constant: String // val not allowed
// lateinit var maybe: String? // nullable not allowed
fun main() { name = "ok"; println(name) }Основы by lazy
by lazy откладывает инициализацию val до первого обращения. Лямбда выполняется один раз, а результат кэшируется.
val expensive: String by lazy {
println("Computing...")
"result"
}
fun main() {
println(expensive) // Computing... then result
println(expensive) // result (cached)
}Зачем использовать by lazy
Используйте by lazy, если инициализация затратна и может не понадобиться: в этом случае результат можно кэшировать для дальнейшего использования. Также этот подход подходит, когда инициализация зависит от уже созданных свойств.
class Config {
val parsed: Map<String, String> by lazy {
println("parsing config...")
mapOf("host" to "localhost", "port" to "8080")
}
}
fun main() {
val c = Config()
println("config object created — not parsed yet")
println(c.parsed["host"]) // now parses
println(c.parsed["port"]) // cached
}Режимы потокобезопасности lazy
По умолчанию by lazy использует LazyThreadSafetyMode.SYNCHRONIZED. Используйте PUBLICATION для инициализации, допускающей параллельный доступ, и NONE для производительности в однопоточном режиме.
val safe: String by lazy { "thread-safe" }
val fast: String by lazy(LazyThreadSafetyMode.NONE) { "fast, single-thread" }
fun main() {
println(safe)
println(fast)
}lateinit и lazy
var, значение присваивается извне. by lazy: val, значение вычисляется самим свойством при первом обращении.class Demo {
lateinit var injected: String // assigned by caller
val computed: String by lazy { "computed once" }
}
fun main() {
val d = Demo()
d.injected = "from outside"
println(d.injected)
println(d.computed)
}Чтение других свойств через lazy
Свойство lazy может читать другие свойства, инициализированные ранее, и объединять их значения.
class User(val first: String, val last: String) {
val fullName: String by lazy { "$first $last" }
}
fun main() {
val u = User("Ada", "Lovelace")
println(u.fullName)
}Практический шаблон
Сочетайте lateinit для внедрения зависимостей и by lazy для производного состояния в одном классе.
class App {
lateinit var config: Map<String, String>
val host: String by lazy { config["host"] ?: "localhost" }
}
fun main() {
val app = App()
app.config = mapOf("host" to "api.example.com")
println(app.host) // api.example.com
}Быстрая проверка
Какое ключевое слово откладывает инициализацию свойства val до первого обращения?
Повторение
Используйте lateinit var для не-null изменяемых свойств, которым фреймворки или DI присваивают значение позже. Используйте val by lazy для доступных только для чтения значений, которые нужно вычислить один раз при первом обращении. Проверяйте состояние с помощью ::prop.isInitialized.
Часто задаваемые вопросы
Урок «lateinit и отложенная инициализация» бесплатный?
Да — полный текст урока «lateinit и отложенная инициализация» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.
Чему я научусь в уроке «lateinit и отложенная инициализация»?
Используйте lateinit для свойств, присваиваемых позднее, а by lazy — для отложенных вычислений. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Kotlin Academy?
Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «lateinit и отложенная инициализация»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Kotlin Academy?
Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Первичный конструктор и параметры-свойства
- Блоки init и порядок инициализации
- Пользовательские геттеры и сеттеры с field
- lateinit и отложенная инициализация