So I read How to run code if object is null? but I don't know yet when to use let,run...etc. I want something like this:
myVar?.xxx{
// do something if is not null
} ?: xxx{
// do something is myVar is null
}
What is the best practice? Thanks :)
CodePudding user response:
The best practice is to not chain scope functions with an Elvis operator to handle null/not null, because it is less readable and it is error-prone. Just because you can do something doesn't mean you should! Inline scope functions provide a lot of power, and therefore also a lot of potential for misuse and less readable code.
For example, the return value of the first scope function (if it is let
or run
) could potentially be null and cause the second scope function to also be run and return something else than you expected.
The question you linked is old, and from a time when there were a lot of new Kotlin users because of Android adopting it as a recommended language. A lot of new users excited about inline scope functions, and probably overly eager to use them as much as possible instead of just where they're the most appropriate tool. Note that in the top-voted answer that shows how it can be done, the advice is still to use if/else because that is more readable.
If myVar
is a local variable (or a locally defined val
property with no custom getter), you should do this:
if (myVar != null) {
// myVar will be smart cast to non-null inside this if block.
//TODO
else {
//TODO
}
If myVar
is a var
property you can do:
myVar.let {
if (it != null) {
// it will be smart cast to non-null inside this if block.
//TODO
else {
//TODO
}
}
// OR
val myLocalVar = myVar
if (myLocalVar != null) {
// myLocalVar will be smart cast to non-null inside this if block.
//TODO
else {
//TODO
}
To get at you specific question, if you were really determined to do this (and you shouldn't!), it would be safest to use myVar.also { } ?: run { }
. The also
function doesn't return a result, but rather returns what it was called on, so there's no risk of accidentally triggering both scope functions. apply
would also work, but typically if you have a whole block of code to run, you don't want to be using it as a receiver. That would be less readable. And for the second scope function, run
makes the most sense because it will not change the receiver from the outer scope, so it creates the least friction to readability here.