What is the best way to write if null then initialize it?

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()
}

1 Like

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.

1 Like

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.

1 Like

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.

7 Likes

Yes, You are right, it’s incorrect.
Just noticed.

2 Likes

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

2 Likes

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
  • Else use lateinit

This is only a quick thought and definately incomplete, if not plain wrong.

2 Likes

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.

2 Likes

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

1 Like

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.