I needed a lazy delegated property that initializes and caches when you get
the property, but allows you to set it to null
to remove that cached result (and re-initialize()
it when you get
it again).
Thanks to the above answer for the code so I could tweak it.
@Suppress("ClassName")
class lazyNullCacheable<T>(val initializer: () -> T) : ReadWriteProperty<Any?, T> {
private object UNINITIALIZED_VALUE
private var prop: Any? = UNINITIALIZED_VALUE
@Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return if (prop == UNINITIALIZED_VALUE || prop == null) {
synchronized(this) {
initializer().also { prop = it }
}
} else prop as T
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
synchronized(this) {
prop = value
}
}
}
Usage :
var prop: String? by lazyNullCacheable {
"string"
}
prop // get prop
prop = null // when you're done using it and want to recalculate / cache it next time
prop // get prop, it will initialize() and cache again
Functionally equivalent to doing something like this (but this is uglier imho)
var _prop: Type? = null
val prop: Type
get() = _prop ?: run {
_prop = Type()
_prop!!
}
prop // get result
_prop = null // clear cache
prop // next get will recalculate it
nullability
andinitialization
. Does your variable have to be nullable? Do you want to initialize this item once and only once? Also, why do you wantvar
and notval
specifically? – InkermanDefaultContextProvider
. That's why I usevar
instead ofval
so I can change it in runtime. I also want to provide a stub strategy (not to mock the whole class) and test all the things. My test dependencies distinguish from the prod ones so it throws an error when it reachesDefaultContextProvider()
. That's the reason of a lazy init. I set the stub strategy inonSetup
before any call to this class and it goes ok except I have to deal with nullability-aware issues. – Roselleroselyn