lazy în Kotlin

Creează o valoare calculată abia la prima folosire, apoi păstrată; se folosește cu val nume by lazy { ... }.

Sintaxă
fun <T> lazy(initializer: () -> T): Lazy<T>
val nume: Tip by lazy { ... }

Ce face lazy

val x by lazy { calcul } declară o proprietate al cărei calcul nu se face la creare, ci prima dată când citești x. Rezultatul este reținut, așa că a doua citire nu mai rulează blocul. Este util pentru valori scumpe (citirea unui fișier, o listă mare) care poate nici nu sunt folosite.

Cuvântul by înseamnă că proprietatea este delegată obiectului returnat de lazy. Funcționează doar cu val, pentru că valoarea nu se mai poate schimba după calcul. Implicit, lazy este sigur pentru mai multe fire de execuție: blocul rulează o singură dată chiar dacă două fire citesc deodată.

Parametri

Parametru Descriere
initializer: () -> T Blocul care calculează valoarea; ultima expresie este valoarea.

Ce returnează

Un obiect Lazy<T>; prin by lucrezi direct cu valoarea de tip T.

Exemple

Exemplul 1: Calculul se face doar la prima citire

Mesajul „Calculez…” apare o singură dată, abia după „Obiect creat”: valoarea este calculată la prima folosire și apoi refolosită.

class Raport(private val vanzari: List<Double>) {
    val total: Double by lazy {
        println("Calculez totalul...")
        vanzari.sum()
    }
}

fun main() {
    val raport = Raport(listOf(120.0, 80.5, 300.0))
    println("Obiect creat")
    println("Total: ${raport.total} lei")
    println("Din nou: ${raport.total} lei")
}

Rezultat

Obiect creat
Calculez totalul...
Total: 500.5 lei
Din nou: 500.5 lei

Exemplul 2: lazy la nivelul unui fișier

Lista de orașe se construiește doar dacă programul ajunge s-o folosească.

val orase: List<String> by lazy {
    println("(încarc lista de orașe)")
    listOf("Iași", "Cluj-Napoca", "Timișoara", "Brașov").sorted()
}

fun main() {
    println("Pornire")
    println(orase.first())
    println(orase.size)
}

Rezultat

Pornire
(încarc lista de orașe)
Brașov
4

Greșeli frecvente

  • Scrii var x by lazy { }. Nu compilează: lazy merge doar cu val. Pentru o variabilă inițializată mai târziu folosește lateinit var.
  • Pui în bloc ceva ce trebuie recalculat la fiecare citire (ora curentă, conținutul unui fișier care se schimbă). lazy calculează o singură dată; pentru recalcul folosește un getter: val x get() = ....

Comenzi înrudite

  • also: Face o acțiune în plus cu un obiect (afișare, verificare, log) și returnează obiectul neschimbat.
  • run: Rulează un bloc în care obiectul este this și returnează rezultatul blocului; with face același lucru, dar primește obiectul ca argument.