Menu
Coddy logo textTech

lazy y lateinit

Parte de la sección Programación orientada a objetos del Journey de Kotlin de Coddy. Lección 10 de 57.

by lazy { ... } retrasa el cálculo de un val hasta que se lee por primera vez y después recuerda el resultado. Es adecuado para valores cuyo cálculo es costoso o que no siempre se necesitan:

class Report(val rows: List<Int>) {
    val summary: String by lazy {
        println("computing summary")
        "total ${rows.sum()}"
    }
}

Dentro de main:

val r = Report(listOf(3, 4))
println("created")
println(r.summary)
println(r.summary)

Salida:

created
computing summary
total 7
total 7

El bloque se ejecuta una vez: la segunda lectura anterior utilizó el resultado almacenado. A diferencia de un getter personalizado, que se ejecuta en cada lectura, lazy calcula una vez y almacena en caché:

class Demo {
    var reads = 0
    val viaGetter: Int
        get() { reads++; return 42 }
    val viaLazy: Int by lazy { reads++; 42 }
}

Dentro de main:

val d = Demo()
repeat(3) { d.viaGetter; d.viaLazy }
println(d.reads)

Salida:

4

lateinit var declara una propiedad no nula que se asigna más tarde, después de la construcción, por ejemplo mediante un método de configuración. Leerla antes de que se haya asignado provoca una excepción, y ::name.isInitialized lo comprueba:

class Screen {
    lateinit var title: String

    fun load(t: String) { title = t }
    fun ready() = ::title.isInitialized
}

Dentro de main:

val s = Screen()
println(s.ready())
s.load("Home")
println(s.ready())
println(s.title)

Salida:

false
true
Home

Prefiere la inicialización simple cuando el valor se conoce en el momento de la construcción. Usa lazy para un val costoso que puede no ser necesario, y lateinit únicamente para un var cuyo valor realmente llega más tarde; lateinit no funciona con Int, Boolean ni otros tipos primitivos.

val config by lazy { loadConfig() }     // calculado en el primer uso, una sola vez
lateinit var user: User                 // asignado después de la construcción
// lateinit var count: Int              // error: no permitido en tipos primitivos
challenge icon

Desafío

Fácil

Completa la clase Document(val text: String). Añade wordCount como una propiedad lazy que cuente las palabras (separadas por espacios simples) y registre cada cálculo sumando 1 a computations, y un lateinit var author: String con un método credit() que devuelva by Ada o by unknown cuando no se haya establecido el autor.

El código proporcionado lee el texto, lee wordCount tres veces, establece el autor cuando hay una segunda línea e imprime words 5, computed 1, by Ada.

Tu código va en Document.kt. Main.kt contiene el código proporcionado de entrada/salida y no se puede editar.

FORMATO DE SALIDA OBLIGATORIO: [Aquí va el contenido traducido]

Pruébalo tú mismo

fun main() {
    // Código de entrada/salida suministrado: déjalo tal como está
    val input = generateSequence(::readLine).toList()
    val doc = Document(input[0])
    val reads = List(3) { doc.wordCount }
    val words = reads.first()
    if (input.size > 1) doc.author = input[1]
    println("words $words, computed ${doc.computations}, ${doc.credit()}")
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Playground de Kotlin