I can't figure out what ?: does in for example this case
val list = mutableList ?: mutableListOf()
and why can it be modified to this
val list = if (mutableList != null) mutableList else mutableListOf()
TL;DR: If the resulting object reference [first operand] is not null, it is returned. Otherwise the value of the second operand (which may be null) is returned. Additionally, the operator can throw an exception if null is returned.
The Elvis operator is part of many programming languages, e.g. Kotlin but also Groovy or C#.
I find the Wikipedia definition pretty accurate:
In certain computer programming languages, the Elvis operator ?: is a binary operator that returns its first operand if that operand is true, and otherwise evaluates and returns its second operand. It is a variant of the ternary conditional operator, ? :, found in those languages (and many others): the Elvis operator is the ternary operator with its second operand omitted.
The following is especially true for Kotlin:
Some computer programming languages have different semantics for this operator. Instead of the first operand having to result in a boolean, it must result in an object reference. If the resulting object reference is not null, it is returned. Otherwise the value of the second operand (which may be null) is returned. If the second operand is null, the operator is also able to throw an exception.
An example:
x ?: y // yields `x` if `x` is not null, `y` otherwise.
x ?: throw SomeException() // yields `x` if `x` is not null, throws SomeException otherwise
The Elvis Operator is represented by a question mark followed by a colon: ?: and it can be used with this syntax:
first operand ?: second operand
It enables you to write a consise code, and works as such:
If first operand isn't null, then it will be returned. If it is null, then the second operand will be returned. This can be used to guarantee that an expression won't return a null value, as you'll provide a non-nullable value if the provided value is null.
For example(in Kotlin):
fun retrieveString(): String { //Notice that this type isn't nullable
val nullableVariable: String? = getPotentialNull() //This variable may be null
return nullableVariable ?: "Secondary Not-Null String"
}
In this case, if the computed value of getPotentialNull is not null, it will be returned by retrieveString; If it is null, the second expression "Secondary Not-Null String" will be returned instead.
Also note that the right-hand side expression is evaluated only if the left-hand side is null.
In Kotlin, you could use any expression as second operand, such as a throw Exception expression
return nullVariable ?: throw IllegalResponseException("My inner function returned null! Oh no!")
The name Elvis Operator comes from the famous American singer Elvis Presley. His hairstyle resembles a Question Mark
Source: Wojda, I. Moskala, M. Android Development with Kotlin. 2017. Packt Publishing
This is called the Elvis operator and it does... Exactly what you've described in your question. If its left hand side is a null value, it returns the right side instead, sort of as a fallback. Otherwise it just returns the value on the left hand side.
a ?: b is just shorthand for if (a != null) a else b.
Some more examples with types:
val x: String? = "foo"
val y: String = x ?: "bar" // "foo", because x was non-null
val a: String? = null
val b: String = a ?: "bar" // "bar", because a was null
Let's take a look at the defintion:
When we have a nullable reference r, we can say "if r is not null, use
it, otherwise use some non-null value x":
The ?: (Elvis) operator avoids verbosity and makes your code really concise.
For example, a lot of collection extension functions return null as fallback.
listOf(1, 2, 3).firstOrNull { it == 4 } ?: throw IllegalStateException("Ups")
?: gives you a way to handle the fallback case elgantely even if you have multiple layers of fallback. If so, you can simply chain multiply Elvis operators, like here:
val l = listOf(1, 2, 3)
val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")
If you would express the same with if else it would be a lot more code which is harder to read.
The elvis operator in Kotlin is used for null safety.
x = a ?: b
In the above code, x will be assigned the value of a if a is not null and b if a is null.
The equivalent kotlin code without using the elvis operator is below:
x = if(a == null) b else a
Simply we can say that, you have two hands. You want to know, is your left hand working right now?. If left hand not working, return empty else busy
Example for Java:
private int a;
if(a != null){
println("a is not null, Value is: "+a)
}
else{
println("a is null")
}
Example for Kotlin:
val a : Int = 5
val l : Int = if (a != null) a.length else "a is null"
Consider below example,
var myStr:String? = null
//trying to find out length of myStr, but it could be null, so a null check can be put as,
val len = if (myStr != null){
myStr.length
}
else{
-1
}
Using the elvis operator, the above code can be written in a single line
val len = myStr?.length ?: -1 // will return -1 if myStr is null else will return length
In addition to what has been already stated there is one good pattern that was not obvious for me, but which is common, e.g. you're writing a long function, but if something is null there is no sense to continue and the only thing you can do is to return from the function. Normally you'd write
something = expression
if (something == null) {
return
}
With elvis it becomes shorter and more elegant:
something = expression ?: return
Basically, if the left side of Elvis returns null for some reason, returns the right side instead.
i.e.
val number: Int? = null
println(number ?: "Number is null")
So, if number is NOT null, it will print number, otherwise will print "Number is null".
A little addition though is this
X = A ?: B
X will still be null if both A and B evaluate to null
Therefore, if you want X to always be non-null, make sure B is always a non-null or that B always evaluates to non-null if it's a function or expression.
I need to condense the following lines in kotlin to a more elegant way. I'm not able to figure out how to check the optional and the values at the same time. Basically I need to verify the list 'a' exists, has one or more items and that they are not 0.
val a = Utils.getItems() // returns an Optional<ImmutableList<ItemChange>>
if(!a.orElse(ImmutableList.of()).size > 0) {
val nonZero = a.get().filter { it.item != BigDecimal.ZERO }
return nonZero.size > 0
}
Assuming you also want to return false if non-existent or size 0, this is how I'd do it.
The any function returns true if any value matches, so it already takes care of the case of an empty list. And it breaks immediately if any match is found, whereas filter will exhaustively check the whole List and allocate a new List to hold the results.
Guava Optional can simply be converted to nullable with orNull() because Kotlin already has null-safety built in.
val items = Utils.getItems().orNull()
return items != null && items.any { it.item != BigDecimal.ZERO }
The following functions produces error. How to use let() or similar null check functions inside a if/for statement.
Here is my code:
fun main() {
var List = listOf<Int>(201, 53 ,5 ,556 ,70 , 9999)
var budget: Int = 500
if(List.min() < 500) { // this line produces the error
println("Yes you can buy from this shop")
}
}
And here is the error:
Operator call corresponds to a dot-qualified call 'List.min().compareTo(500)' which is not allowed on a nullable receiver 'List.min()'.
Help me with nullable types. Thank you
The question here is: what do you want to happen if your list is empty?
If a list has one or more items, and those items are comparable, then you can always find a minimum. (It doesn't have to be unique.) But if the list has no items, then there is no minimum. So what do you want to happen then? Do you want to continue with a ‘default’ value? Or skip that block? Or something else?
If you want a default value, then you can use the elvis operator:
if ((list.minOrNull() ?: 0) < 500)
println("Yes you can buy from this shop")
That substitutes the value 0 if the list is empty. (It doesn't have to be zero; any value will do. In fact, this can work with any type as long as it's Comparable.)
Or you could do an explicit check for the list being empty:
if (list.isEmpty()) {
// Do something else
} else if (list.minOrNull()!! < 500)
println("Yes you can buy from this shop")
The !! non-null assertion operator works here, but it's a code smell. (It's easy to miss when you're changing surrounding code; it could then throw a NullPointerException.) So it's safer to handle the null. Perhaps the most idiomatic way is with let():
list.minOrNull().let {
if (it == null) {
// Do something else
} else if (it < 500)
println("Yes you can buy from this shop")
}
(The < check is allowed there, because by that point the compiler knows it can't be null.)
Or if you just want to avoid the check entirely, use a ?. safe-call so that let() is only called on a non-null value:
list.minOrNull()?.let {
if (it < 500)
println("Yes you can buy from this shop")
}
I'm creating a chat app and don't want to display the user avatar over and over if a user sends multiple messages consecutively.
The user messages are stored in a Map, where the newest message has the index 0.
To check if a message at an index is sent by the same person as the message before, I use the following method:
bool _sameUser () {
if (index > 0 && map != null && map[index + 1] != null && map[index + 1]['fromUser’] == map[index][‘fromUser’]) {
return true;
} else {
return false;
}
}
However, this doesn't work for the newest message or if there are more than two messages from the same user.
How I can rewrite the conditional so it works as intended?
Thanks!
UPDATE:
After try #Marcel answer and test more I find another issue maybe cause this.
map[index + 1] != null is not true even when message 2 is send. Is only true after message 3 is send.
I test with conditional in function:
if (map[index + 1] != null) {
print('!=null');
}
There's no reason your code shouldn't work for the index 0 except you test index > 0.
By removing that, it should work fine:
bool _sameUser () {
assert(index >= 0);
assert(map != null);
return map[index + 1] != null && map[index + 1]['fromUser'] == map[index]['fromUser'];
}
Because I assumed, the index should never be smaller than 0 and the map should never be null, I moved some of the condition code to assert statements.
Also, because your if-expression is a boolean, you can just return it directly.
In the sample below, the function should return a non-null data.
Since the data could be changed in the process, it needs to be var, and can only be nullable to start with.
I can't use lateinit because the first call of if (d == null) will throw.
After the process it will be assigned a non-null data, but the return has to use the !! (double bang or non-null assertion operator).
What is the best approach to avoid the !!?
fun testGetLowest (dataArray: List<Data>) : Data {
var d: Data? = null
for (i in dataArray.indecs) {
if (d == null) {// first run
d = dataArray[i]
} else if {
d.level < dataArray[i].level
d = dataArray[i]
}
}
return d!!
}
If you don't like !! then supply a default value for it. You'll realize you can only supply the default value if the list is not empty, but, as you said, the list is already known to be non-empty. The good part of this story is that the type system doesn't track list size so when you say dataArray[0], it will take your word for it.
fun testGetLowest(dataArray: List<Data>) : Data {
var d: Data = dataArray[0]
for (i in 1 until dataArray.size) {
if (d.level < dataArray[i].level) {
d = dataArray[i]
}
}
return d
}
Normally, you can and should lean on the compiler to infer nullability. This is not always possible, and in the contrived example if the inner loop runs but once d is non-null. This is guaranteed to happen if dataArray has at least one member.
Using this knowledge you could refactor the code slightly using require to check the arguments (for at least one member of the array) and checkNotNull to assert the state of the dataArray as a post-condition.
fun testGetLowest (dataArray: List<Data>) : Data {
require(dataArray.size > 0, { "Expected dataArray to have size of at least 1: $dataArray")
var d: Data? = null
for (i in dataArray.indecs) {
if (d == null) {// first run
d = dataArray[i]
} else if {
d.level < dataArray[i].level
d = dataArray[i]
}
}
return checkNotNull(d, { "Expected d to be non-null through dataArray having at least one element and d being assigned in first iteration of loop" })
}
Remember you can return the result of a checkNotNull (and similar operators):
val checkedD = checkNotNull(d)
See Google Guava's Preconditions for something similar.
Even if you were to convert it to an Option, you would still have to deal with the case when dataArray is empty and so the value returned is undefined.
If you wanted to make this a complete function instead of throwing an exception, you can return an Option<Data> instead of a Data so that the case of an empty dataArray would return a None and leave it up to the caller to deal with how to handle the sad path.
How to do the same check, and cover the empty case
fun testGetLowest(dataArray: List<Data>)
= dataArray.minBy { it.level } ?: throw AssertionError("List was empty")
This uses the ?: operator to either get the minimum, or if the minimum is null (the list is empty) throws an error instead.
The accepted answer is completly fine but just to mentioned another way to solve your problem by changing one line in your code: return d ?: dataArray[0]