0Pricing
Kotlin Academy · Lesson

by lazy: Deferred Initialization Deep Dive

Explore lazy initialization modes: SYNCHRONIZED, PUBLICATION, and NONE.

by lazy: Deferred Initialization Deep Dive is a free Kotlin Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is by lazy?

by lazy defers initialization of a val until first access. The lambda runs once and caches the result.

val greeting: String by lazy {
    println("Computing...")
    "Hello, Kotlin!"
}
fun main() {
    println(greeting) // prints Computing... then Hello, Kotlin!
    println(greeting) // prints Hello, Kotlin! (cached)
}

Lazy Syntax

The by lazy delegate takes a lambda returning the value type inferred from the property declaration.

val pi: Double by lazy { Math.PI }
val appName: String by lazy { "MyApp v1.0" }
fun main() {
    println(pi)      // 3.141592653589793
    println(appName) // MyApp v1.0
}

SYNCHRONIZED Mode (Default)

By default, lazy uses LazyThreadSafetyMode.SYNCHRONIZED: only one thread initializes the value.

val heavyResource: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
    Thread.sleep(100) // simulate work
    "Resource ready"
}
fun main() { println(heavyResource) }

PUBLICATION Mode

PUBLICATION allows multiple threads to initialize concurrently; the first result wins. Use when initialization is cheap and side-effect-free.

val config: Map<String, String> by lazy(LazyThreadSafetyMode.PUBLICATION) {
    mapOf("host" to "localhost", "port" to "8080")
}
fun main() { println(config["host"]) }

NONE Mode

NONE has no synchronization overhead. Use only in single-threaded contexts where performance matters.

val singleThreadValue: Int by lazy(LazyThreadSafetyMode.NONE) {
    42
}
fun main() { println(singleThreadValue) }

Lazy in a Class

by lazy inside a class initializes on first property access, useful for expensive computations tied to instance state.

class DatabaseConnection(val url: String) {
    val pool: String by lazy {
        println("Connecting to $url")
        "Pool@$url"
    }
}
fun main() {
    val db = DatabaseConnection("localhost:5432")
    println(db.pool)
}

Lazy vs lateinit

Use by lazy for val with complex initialization. Use lateinit for var assigned externally (e.g., in tests or dependency injection).

class MyService {
    val computed: List<Int> by lazy { (1..100).toList() }
    lateinit var injected: String
}
fun main() {
    val s = MyService()
    s.injected = "injected value"
    println(s.computed.size)
    println(s.injected)
}

isInitialized Check

Check if a lazy property has been initialized with .isInitialized() — but only via the delegate reference.

val myLazy: String by lazy { "initialized" }
fun main() {
    val ref = ::myLazy
    // No direct isInitialized on val lazy, but we can check via delegate
    println(myLazy)
}

Lazy with Dependency

Lazy properties can reference other lazy properties, building a lazy initialization chain.

val baseUrl: String by lazy { "https://api.example.com" }
val usersUrl: String by lazy { "$baseUrl/users" }
val postsUrl: String by lazy { "$baseUrl/posts" }
fun main() {
    println(usersUrl)
    println(postsUrl)
}

Practical: Singleton Service

Use by lazy in object declarations to initialize heavyweight singletons on demand.

object Analytics {
    val client: String by lazy {
        println("Initializing analytics client")
        "AnalyticsClient@ready"
    }
}
fun main() {
    println("App started")
    println(Analytics.client) // initialized on first use
    println(Analytics.client) // cached
}

Lazy Regex Compilation

Compiling regex is expensive. Use by lazy to compile once and reuse, avoiding repeated overhead.

val emailRegex: Regex by lazy {
    Regex("^[A-Za-z0-9+_.-]+@(.+)$")
}
fun isValidEmail(email: String) = emailRegex.matches(email)
fun main() {
    println(isValidEmail("user@example.com")) // true
    println(isValidEmail("bad-email"))         // false
}

Quick Check

Which lazy mode should you use in a single-threaded environment for maximum performance?

Recap

by lazy runs its lambda once on first access and caches the result. Choose SYNCHRONIZED (default) for thread safety, PUBLICATION for concurrent idempotent init, and NONE for single-threaded performance.

Frequently asked questions

Is the “by lazy: Deferred Initialization Deep Dive” lesson free?

Yes — the full text of “by lazy: Deferred Initialization Deep Dive” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.

What will I learn in “by lazy: Deferred Initialization Deep Dive”?

Explore lazy initialization modes: SYNCHRONIZED, PUBLICATION, and NONE. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “by lazy: Deferred Initialization Deep Dive” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. by lazy: Deferred Initialization Deep Dive
  2. observable and vetoable Delegates
  3. Writing a Custom ReadWriteProperty Delegate
  4. Delegates for Preferences, Map-Backed Properties & Logging
← Back to Kotlin Academy