In the lesson, you learned about Delegated properties. Now, look into one of the cases when these properties are valuable.
Imagine you’re building an app that displays user profiles. Downloading profile pictures can take time, and you don’t want to slow down your app’s launch for something a user might not even view right away. This is where lazy properties shine!
Lazy properties are like resourceful assistants. They wait until you actually need something before fetching it. In the example, the profile picture wouldn’t be downloaded until the user taps on their profile. This keeps your app snappy and efficient.
Lazy properties are also great for computationally expensive calculations. Why waste processing power calculating something a user might not need? With lazy properties, the calculation is put off until it’s truly required.
Add this example of a Rectangle class that uses width and length to calculate the area and perimeter. These calculations will happen every time you use them.
class Rectangle(val length: Double, val width: Double) {
val area: Double
get() = (length * width).also { println("Calculating area") }
val perimeter: Double
get() = 2 * (length + width).also { println("Calculating perimeter") }
}
In this example, area and perimeter are not calculated when a Rectangle class instance is created, but every time we use them, they’re being calculated.
fun main() {
val rectangle = Rectangle(5.0, 3.0)
println("Area: ${rectangle.area}")
// Calculating area
// Area: 15.0
println("Area: ${rectangle.area}")
// Calculating area
// Area: 15.0
println("Perimeter: ${rectangle.perimeter}")
// Calculating perimeter
// Perimeter: 16.0
println("Perimeter: ${rectangle.perimeter}")
// Calculating perimeter
// Perimeter: 16.0
}
If the rectangle’s length and width are unchanged, the area and perimeter stay the same and need calculations only once, in other words be lazy.
Change area definition to this:
val area: Double by lazy {
(length * width)
.also {
println("Calculating area")
}
}
Now the area property in your Rectangle class is using the by lazy { } pattern. The curly braces hold a lambda expression, that you should know from Module 3, a fancy way of saying it’s a block of code that calculates the value of area and prints statement. But the key here is the lazy part. It instructs Kotlin to wait until the property is actually accessed before running the initialization code.
And run the code again. Output will be:
Calculating area
Area: 15.0
Area: 15.0
Calculating perimeter
Perimeter: 16.0
Calculating perimeter
Perimeter: 16.0
As you can see, the area calculation happened only once! This is in contrast to the length and width properties, which are a regular properties. Every time you ask for the area or perimeter, it calculates the value using the length of the sides. This might be unnecessary if you only need the area once.
Lazy properties are like efficient assistants. They calculate things only when you need them, preventing redundant work. In the Rectangle example, area is a constant value for the given length and width, so there’s no reason to calculate it repeatedly, saving your time and effort. The usage val keyword makes this clear.
Now it’s your turn to fix the perimeter methods. Give it a try, change the perimeter definition and see if output will be like this:
Calculating area
Area: 15.0
Area: 15.0
Calculating perimeter
Perimeter: 16.0
Perimeter: 16.0