Menu
Coddy logo textTech

lazy e lateinit

Parte da seção Programação Orientada a Objetos do Journey de Kotlin da Coddy. Lição 10 de 57.

by lazy { ... } adia o cálculo de um val até que ele seja lido pela primeira vez e, então, memoriza o resultado. É adequado para valores que são custosos ou nem sempre necessários:

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)

Saída:

created
computing summary
total 7
total 7

O bloco é executado uma vez: a segunda leitura acima usou o resultado armazenado. Diferentemente de um getter personalizado, que é executado em cada leitura, lazy calcula uma vez e armazena em cache:

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)

Saída:

4

lateinit var declara uma propriedade não nula que é atribuída posteriormente, após a construção, por exemplo, por um método de configuração. Lê-la antes de ser atribuída lança uma exceção, e ::name.isInitialized verifica isso:

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)

Saída:

false
true
Home

Prefira a inicialização direta quando o valor for conhecido na construção. Use lazy para um val dispendioso que pode não ser necessário, e lateinit somente para um var cujo valor realmente seja definido mais tarde; lateinit não funciona com Int, Boolean ou outros tipos primitivos.

val config by lazy { loadConfig() }     // computado no primeiro uso, uma vez
lateinit var user: User                 // atribuído após a construção
// lateinit var count: Int              // erro: não permitido em tipos primitivos
challenge icon

Desafio

Fácil

Complete a classe Document(val text: String). Adicione wordCount como uma propriedade lazy que conta as palavras (separadas por espaços simples) e registra cada cálculo adicionando 1 a computations, e uma lateinit var author: String com um método credit() que retorna by Ada ou by unknown quando o autor não tiver sido definido.

O código fornecido lê o texto, lê wordCount três vezes, define o autor quando uma segunda linha está presente e imprime words 5, computed 1, by Ada.

Seu código deve ser colocado em Document.kt. Main.kt contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

fun main() {
    // Código de entrada/saída fornecido: mantenha-o 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 iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Playground de Kotlin