What is the best way to write below code in Kotlin.
I’m not looking to write any extra function to make it more smart.
Looking if Kotlin has some smart way to write it.
…
if(list == null){
list = ArrayList()
}
…
I think your version is probably still the best. The one alternative I have is
list = list ?: ArrayList()
The problem with that is, that if the property has a custom setter it will be triggered even though the value is the same. This might lead to issues in some cases.
Is it below…
list?.let {
list = ArrayList()
}
I think your and @Wasabi375’s are both perfectly fine. No need to overcomplicate the simple things. Personally I wouldn’t use your ?.let example because it seems a little less readable.
Agreed. You shouldn’t be using let
unless you use the it
parameter for anything. Otherwise it just confuses the reader as to why let
was used. Maybe you could use list?.run {}
but even that seems strange. Sometimes a simple if
is just the best way to go.
Wait, am I missing something???
if(list == null){
list = ArrayList()
}
isn’t the same as
list?.let {
list = ArrayList()
}
The last code would be
if(list != null){
list = ArrayList()
}
Or am I mistaken?
using ?:
instead of ?.
would make it equal to the the first code.
Yes, You are right, it’s incorrect.
Just noticed.
Depending on what you’re trying to do in context, there’s another possibility: you could use a lazily-initialised property, like this.
val list : ArrayList by lazy { ArrayList() }
This will create an object to hold the lambda, bit won’t create the list until the first time your code accesses the property. See https://kotlinlang.org/docs/reference/delegated-properties.html#lazy
This probably doesn’t fit the bill for what Sandeep intended since I think his intent was having a mutable variable that could be written to and if not written to initialize it to an empty list.
A property delegate could be written to fit the bill, but I’m not sure how it would be any better than just:
var list : List = listOf()
I would probably define the list
as non-nullable using a delegate and later assign it a value.
Something like this:
private var list by Delegates.notNull<List<Any>>()
fun onLoad()
{
list = listOf()
}
I won’t.
Creating a list is not that expensive.
Therefor i would prefer to set the list in the field immediately if you don’t have to check if it’s null.
Just a couple of lines I came up with in a matter of minutes:
- If it’s normal for the type to be null during the logic, use nullable.
- Else if the variable is set from outside the class, use lateinit.
- Else if the variable can be set without parameters known at class creation:
- if the variable-creation is heavy and not always needed: use Lazy
- else create immediately
- If creating the variable does need parameters that aren’t known during class initialization:
- Can you use SingleTonHolder or a similar pattern? use it.
Also check if the class refering to the variable is secretly standalone and should be placed in a different class
- Can you use SingleTonHolder or a similar pattern? use it.
- Else use
lateinit
This is only a quick thought and definately incomplete, if not plain wrong.
A bit off topic, but I think there is one thing missing with “lateinit”. I really like the concept, but I also love to use val
instead of var
whenever possible. I sometimes need lateinit for a variable that I only ever want to set once. I normally add this delegate for that case
fun <T: Any> lateinitVal() = LateInitVal<T>()
class LateInitVal<T : Any> : ReadWriteProperty<Any?, T> {
val isInitialized: Boolean get() = value != null
private var value: T? = null
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
check(this.value == null) {
"Property ${property.name} can only be set once."
}
this.value = value
}
}
var foo by lateinitVal<Foo>()
foo = Foo() // :)
foo = Foo() // throws exception
I know this doesn’t add compile time checks but it’s still quite usefull in my experience.
If you wanna avoid calling the custom setter then you could instead do something like:
list ?: run { list = ArrayList() }
But again, I think
if(list == null) { ... }
Is probably more standard
My habit is something like this:
return foo ?: Foo(bar).also { foo = it }
BTW, I also think the old fashion java style is acceptable:
if (foo == null) {
foo = Foo(bar)
}
return foo!!
This is for cases where your initializer takes some param, otherwise lazy
works perfectly.