Menu
Coddy logo textTech

lazy e lateinit

Fa parte della sezione Programmazione orientata agli oggetti del percorso Kotlin di Coddy. Lezione 10 di 57.

by lazy { ... } rimanda il calcolo di un val fino alla prima lettura, poi ne memorizza il risultato. È adatto a valori il cui calcolo è costoso o che non sono sempre necessari:

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

All'interno di main:

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

Output:

created
computing summary
total 7
total 7

Il blocco viene eseguito una sola volta: la seconda lettura qui sopra ha usato il risultato memorizzato. A differenza di un getter personalizzato, che viene eseguito a ogni lettura, lazy calcola una volta e memorizza il risultato nella cache:

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

All'interno di main:

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

Output:

4

lateinit var dichiara una proprietà non nullable a cui viene assegnato un valore in seguito, dopo la costruzione, per esempio tramite un metodo di configurazione. Leggerla prima che le venga assegnato un valore genera un'eccezione, mentre ::name.isInitialized verifica se è stata inizializzata:

class Screen {
    lateinit var title: String

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

All'interno di main:

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

Output:

false
true
Home

Preferisci un’inizializzazione semplice quando il valore è noto al momento della costruzione. Usa lazy per un val costoso che potrebbe non essere necessario e lateinit solo per un var il cui valore arriva davvero in seguito; lateinit non funziona con Int, Boolean o altri tipi primitivi.

val config by lazy { loadConfig() }     // calcolato al primo utilizzo, una sola volta
lateinit var user: User                 // assegnato dopo la costruzione
// lateinit var count: Int              // errore: non consentito per i tipi primitivi
challenge icon

Sfida

Facile

Completa la classe Document(val text: String). Aggiungi wordCount come proprietà lazy che conta le parole (separate da spazi singoli) e registra ogni calcolo aggiungendo 1 a computations, e una lateinit var author: String con un metodo credit() che restituisce by Ada oppure by unknown quando l'autore non è stato impostato.

Il codice fornito legge il testo, legge wordCount tre volte, imposta l'autore quando è presente una seconda riga e stampa words 5, computed 1, by Ada.

Il tuo codice va in Document.kt. Main.kt contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

fun main() {
    // Codice di input/output fornito: lascialo così com'è
    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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Playground Kotlin