0Pricing
Kotlin Academy · Урок

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

lateinit: 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 — локальная установка не требуется.

Все уроки этого курса

  1. Первичный конструктор и параметры-свойства
  2. Блоки init и порядок инициализации
  3. Пользовательские геттеры и сеттеры с field
  4. lateinit и отложенная инициализация
← Назад к Kotlin Academy