apply()
Most programmers have run into cases where they had to repeat a reference to a variable or something a lot:
import java.util.Calendar
val sometime = Calendar.getInstance()
sometime.set(Calendar.YEAR, 1980)
sometime.set(Calendar.MONTH, 1)
sometime.set(Calendar.DAY_OF_MONTH, 22)
sometime.set(Calendar.HOUR_OF_DAY, 17)
sometime.set(Calendar.MINUTE, 0)
sometime.set(Calendar.SECOND, 0)
sometime.set(Calendar.MILLISECOND, 0)
println(sometime)
You have some object and you need to call a whole bunch of methods on it to configure it, such as setting the individual fields of a Calendar
object, as we are doing here.
We could simplify this with let()
:
import java.util.Calendar
val sometime = Calendar.getInstance()
sometime.let {
it.set(Calendar.YEAR, 1980)
it.set(Calendar.MONTH, 1)
it.set(Calendar.DAY_OF_MONTH, 22)
it.set(Calendar.HOUR_OF_DAY, 17)
it.set(Calendar.MINUTE, 0)
it.set(Calendar.SECOND, 0)
it.set(Calendar.MILLISECOND, 0)
}
println(sometime)
However, apply()
works even better for this scenario. You call it on some object, supplying a lambda expression. The object becomes this
inside of the lambda expression, allowing you to just call functions on it without having to name it.
Alas, Kotlin/JS does not have java.util.Calendar
, so we cannot use that in the Klassbook. So, let’s look at an alternative construct:
data class IntPropertyBag(private val pieces: MutableMap<String, Int> = mutableMapOf()) {
fun set(key: String, value: Int) {
pieces[key] = value
}
}
fun main() {
val sometime = IntPropertyBag()
sometime.apply {
set("ID", 330258648)
set("YEAR", 1979)
set("HOW_MANY_ROADS_MUST_A_MAN_WALK_DOWN", 42)
}
println(sometime)
}
Here, pretend that IntPropertyBag
is some truly awful class that you are getting from some third-party library. You have no choice but to use it, despite the fact that it’s API is fairly limited: you can give it one named integer at a time via set()
. Here, rather than spell out the sometime.
part of calling set()
three times to set three integer properties, we use apply()
to make this
be the bag, so we can call set()
without referencing the bag directly.
Also, apply()
returns whatever object that you called it on, so we can further simplify this as:
data class IntPropertyBag(private val pieces: MutableMap<String, Int> = mutableMapOf()) {
fun set(key: String, value: Int) {
pieces[key] = value
}
}
fun main() {
val ultimateStuff = IntPropertyBag().apply {
set("ID", 330258648)
set("YEAR", 1979)
set("HOW_MANY_ROADS_MUST_A_MAN_WALK_DOWN", 42)
}
println(ultimateStuff)
}
This is the same as the previous example, except that we are just chaining apply()
right onto the call to the IntPropertyBag
constructor.
Of course, we could also put the println()
in here:
val ultimateStuff = IntPropertyBag().apply {
set("ID", 330258648)
set("YEAR", 1979)
set("HOW_MANY_ROADS_MUST_A_MAN_WALK_DOWN", 42)
println(this)
}
Or, we could eliminate ultimateStuff
entirely:
println(IntPropertyBag().apply {
set("ID", 330258648)
set("YEAR", 1979)
set("HOW_MANY_ROADS_MUST_A_MAN_WALK_DOWN", 42)
})
In summary, apply()
:
- Is called on some object
- Takes whatever you call it on and makes it be the “current” object —
this
— in the scope of the lambda expression - Returns whatever object you called it on
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.