lazy and lateinit
Part of the Object Oriented Programming section of Coddy's Kotlin journey. Lesson 10 of 57.
by lazy { ... } delays the computation of a val until it is first read, then remembers the result. It fits values that are expensive or not always needed:
class Report(val rows: List<Int>) {
val summary: String by lazy {
println("computing summary")
"total ${rows.sum()}"
}
}Inside main:
val r = Report(listOf(3, 4))
println("created")
println(r.summary)
println(r.summary)Output:
created
computing summary
total 7
total 7The block runs once: the second read above used the stored result. Unlike a custom getter, which runs on every read, lazy computes once and caches:
class Demo {
var reads = 0
val viaGetter: Int
get() { reads++; return 42 }
val viaLazy: Int by lazy { reads++; 42 }
}Inside main:
val d = Demo()
repeat(3) { d.viaGetter; d.viaLazy }
println(d.reads)Output:
4lateinit var declares a non-null property that is assigned later, after construction, for example by a setup method. Reading it before it is assigned throws an exception, and ::name.isInitialized checks it:
class Screen {
lateinit var title: String
fun load(t: String) { title = t }
fun ready() = ::title.isInitialized
}Inside main:
val s = Screen()
println(s.ready())
s.load("Home")
println(s.ready())
println(s.title)Output:
false
true
HomePrefer plain initialization when the value is known at construction. Use lazy for a costly val that may not be needed, and lateinit only for a var whose value truly arrives later; lateinit does not work with Int, Boolean or other primitive types.
val config by lazy { loadConfig() } // computed on first use, once
lateinit var user: User // assigned after construction
// lateinit var count: Int // error: not allowed on primitive typesChallenge
EasyComplete the class Document(val text: String). Add wordCount as a lazy property that counts the words (separated by single spaces) and records each computation by adding 1 to computations, and a lateinit var author: String with a method credit() that returns by Ada or by unknown when the author has not been set.
The supplied code reads the text, reads wordCount three times, sets the author when a second line is present, and prints words 5, computed 1, by Ada.
Your code goes in Document.kt. Main.kt holds the supplied input/output code and cannot be edited.
Try it yourself
fun main() {
// Supplied input/output code: keep it as it is
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()}")
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesPrimary Constructorsinit Blocks and ValidationSecondary ConstructorsRecap - Library Card4Inheritance
Open Classes and SubclassesOverriding Memberssuper and ConstructorsAbstract ClassesRecap - Staff Directory2Properties and Encapsulation
Custom AccessorsVisibility ModifiersPrivate Setterslazy and lateinitRecap - Bank Account5Interfaces
Declaring InterfacesDefault MethodsMultiple InterfacesInterfaces as TypesRecap - Payment Methods8Generics
Generic FunctionsGeneric ClassesType ConstraintsVariance With in and outRecap - Priority Queue11Project: Library Management
Books and MembersBorrowing BooksPractice on your own: Kotlin playground