I'm searching for the (idiomatic) Kotlin equivalent to javas:
private static Book currentBook;
public static Book get() {
if(currentBook == null) {
currentBook = new Book();
}
return currentBook;
}
public static void set(Book book) {
if(currentBook != null) {
throw IllegealStateException()
}
currentBook = book
}
My guess was
companion object {
var currentBook: Book? = null
get(): Book? {
if (field == null) {
field = Book()
}
return field
}
set(value) {
if(field != null) {
throw IllegalStateException()
}
field = value
}
}
The thing that bothers me is that currentBook
is always non-null although I need to declared the type as nullable Book?
to allow the default initialization with null
.
Is there a proper way for a static property currentBook
that is of non-nullable type Book
?
You can also use a separate backing field, instead of using field
. Then, currentBook
can be non-nullable.
private var _currentBook: Book? = null
var currentBook: Book
get() = _currentBook ?: Book().also { _currentBook = it }
set(value) {
if(_currentBook != null) {
throw IllegalStateException()
}
_currentBook = value
}
It seems like what you are trying to write is the lazy { ... }
property delegate, but also allowing manually setting a different initial value. You can write this as a property delegate too. (Adapted from Lazy.kt)
class MutableLazy<T>(initializer: () -> T) : Lazy<T> {
private object UNINITIALIZED_VALUE
private var initializer: (() -> T)? = initializer
private var _value: Any? = UNINITIALIZED_VALUE
override var value: T
get() {
if (_value === UNINITIALIZED_VALUE) {
_value = initializer!!()
initializer = null
}
@Suppress("UNCHECKED_CAST")
return _value as T
}
set(value) {
if(_value !== UNINITIALIZED_VALUE) {
throw IllegalStateException()
}
_value = value
initializer = null
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
_value = value
}
}
fun <T> mutableLazy(initializer: () -> T): MutableLazy<T> = MutableLazy(initializer)
Usage:
var currentBook: Book by mutableLazy { Book() }