Let's say I have an object Response. Now I would like to check a boolean variable, success, under Response and do an early return is response is not successful.
if(response == null || !response.success){
return;
} //Java version
Now I would like to use Kotlin's null safety check like following
if(response?.success ?: true){
return
}
If I'm not wrong, if either response or success is null we'll return true inside the if condition. However, if response.success is not null and equals to true, we will still return from the function, which is not what I want . How do I correct this condition ?
I think you have to do
if(!(response?.success ?: false)){
return // null or failed
}
which is equivalent to your java version.
but note: if the null check version is easier to read. You can use that in Kotlin too
you can also flip the condition
response?.success?.let {
// do something when success
}
see the Elvis operator doc for more info
Quite old question, but I just stumbled over it.
The following may be the shortest if clause:
if (response?.success != true) {
//There is either no response, or it was not successful
}
Related
Am checking whether value returned by a function is a snapshot in Kotlin as indicated below, however I would like to check for the exception first(ie when it is not a snapshot). I have tried using !=, equal(), but they all compare but can't check datatype. How can I get the else part first?
if (it is Snapshot) {
} else {
}
You can negate the is operator with !is:
if (it !is Snapshot) {
// not a Snapshot
} else {
}
The doc for this is in the hard keywords section.
I implemented a LinkedList in kotlin and wrote a method to remove duplicates from it:
class Node (value:Int) {
var value = value
var next:Node? = null
fun addNodeToTail(value:Int){
var node = this
while (node.next != null) {
node = node.next
}
val newNode= Node(value)
node.next= newNode
}
fun removeDuplicates (){
val set = HashSet<Int>()
var node = this
set.add(node.value)
while(node.next != null){
if (set.contains(node.next?.value)){
node.next= node.next?.next
}else{
set.add(node.next.value)
node= node.next
}
}
}
}
In the last two lines:
set.add(node.next.value)
node= node.next
(and in the addNodeToTail method), the compiler says that smart cast is impossible because of complex expression. I have to add non-null asserted call (!!).
I want to understand why this solution is not accepted, although the while expression checks that node.next is not null. And I want to know if there is a better solution than using non-null asserted call (!!).
Thank you for your help
Pawel technically answered in the comment.
Basically smart casts are not always possible. In particular, if you define a mutable var of nullable type that is technically accessible by multiple threads, the compiler cannot guarantee that the value stays the same between the null check and the usage. That's why you get this error "smart cast impossible".
A common way of dealing with the problem is to store the value in a local val variable, to guarantee that this value will not change, and allow the compiler to smart cast it.
In your case though, it's not ideal because the while has to check the actual node's value every time. So you'll have to assert that the value is not null at some point, either with !! or with an elvis (?:) and an error() or throw.
I would personally go for:
while (node.next != null) {
val nextNode = node.next ?: throw ConcurrentModificationException()
if (set.contains(nextNode.value)) {
node.next = nextNode.next
} else {
set.add(nextNode.value)
node = nextNode
}
}
bitmap1 = Bitmap.createScaledBitmap(
bitmap1, // <---- error is here
(width.toInt()),
(height.toInt()),
false)
numberOfInvaders ++
I also used bitmap2 and bitmap 1 in another class :
if (uhOrOh) {
canvas.drawBitmap(Invader.bitmap1, // <--- error is here
invader.position.left,
invader.position.top,
paint)
} else {
canvas.drawBitmap(Invader.bitmap2, // <---- and here
invader.position.left,
invader.position.top,
paint)
}
here its says : Type mismatch,
Required:Bitmap Found: Bitmap?
Yup, that's true :) You cannot use value like this, because it can be null at some point.
createScaledBitmap requires nonnullable Bitmap, but there is no guarantee that bitmap you use won't be null at the moment of calling given function.
So, what you can do?
Before the call check if bitmap is not null:
if (bitmap != null) { /* code here, still requires !! operator */ }
In multithreaded environment there is a risk that during execution of code block a value will change anyway, so you can use let function with ?. operator (basically the same operator like ., but executes only if value is not null). The block code will be invoked with an effectively final argument which is an instance you use to call this method, in this case "bitmap", called "context object", accessible via it keyword:
bitmap?.let { /* code here, bitmap is passed as effectively final, so for sure it's not null */ }
There other way would be !! operator (but it can finish with NPE exception, if value is null). Use only if you are sure that this value at that moment won't be null, otherwise you can crash your application.
Also, you can use ?: operator - this will take first value if not null, otherwise the second. It's quite nice, because you can use for example default value. Also, you can throw exception there ;)
bitmap ?: throw IllegalStateException("bitmap is null") // exception
bitmap ?: DEFAULT_BITMAP // default bitmap, if any
In this case you will get exception but with very communicative message (instead of just NPE).
bitmap1 = Bitmap.createScaledBitmap(
bitmap1!!, // !! <--- helps
(width.toInt()),
(height.toInt()),
false)
numberOfInvaders ++
if (uhOrOh) {
canvas.drawBitmap(Invader.bitmap1!!, // here
invader.position.left,
invader.position.top,
paint)
} else {
canvas.drawBitmap(Invader.bitmap2!!, // and here too
invader.position.left,
invader.position.top,
paint)
}
In Kotlin I have this (which will not compile):
var list: MutableList<String>? = null
if (list.isNotEmpty()) {
}
This will compile:
var list: MutableList<String>? = null
if (list!!.isNotEmpty()) {
}
However, if list is null, a runtime exception will occur. I could do this:
var list: MutableList<String>? = null
if ((list != null) && list.isNotEmpty()) {
}
But this seems to be repetitive everywhere you need to test if something is null. Is there a more eloquent way of doing this in Kotlin?
In the specific case of checking if the list is not null or empty you can use:
if (!list.isNullOrEmpty())
For a list, it's better to avoid handling null state instead handle only empty and non-empty state. refer http://thefinestartist.com/effective-java/43.
Saying that, we don't need to explicitly check for null check and only empty check alone should do the trick.
var list : MutableList<String> = mutableListOf()
list.add("Test1")
list.takeIf { it.isNotEmpty() }?.forEach { println(it) }
We can use
takeIf
to check whether the list is empty or not.
The first way add this line
list = list?:MutableList<String>()
Second way
val isEmpty = list.isEmpty()?:false
if(isEmpty){}else{}
Third way
if (!list.isNullOrEmpty())
as #AndroidDev suggested
Why are getting an error? Since !! require non-null. if the object is null then it will throw NPE
I think most can be done with the safe operator ?. itself. So if you just want to iterate over the list (or reduce, map, or whatever), you can just simply do so directly:
val sumExpression = list?.joinToString("+") { it.someValue } ?: throw exception? use default value?
list?.forEach { println("an entry in the list: $it") } // if there are entries, just iterate over them... if not, there is nothing to do
list?.also {
consume(it) // consume now is only called if the list is not null
}
Enhancing it then with a condition is also rather easy with takeIf or takeUnless (depending on what you require):
list?.takeIf { it.isNotEmpty() }
Now you still have a nullable list and can again call any of the desired functions as shown before:
list?.takeIf( it.isNotEmpty() }?.also {
consume(it)
}
Also a variant instead of list.isNullOrEmpty() (already shown by gpuntos answer) is to compare the possible null value to the expected outcome, e.g.:
if(list?.isNotEmpty() == true) {
// do something with the non-empty list
}
In case it is null the condition simplifies to basically null == true which is false. However I wouldn't overuse that too much as then you don't see the actual nullable types so easily anymore. Such a usage may make sense, if what you are trying to calculate isn't already supported in its own extension function (as is with isNullOrEmpty()), e.g. for entering the if only if the count is 4 it makes sense to use something like: if (list?.count() == 4)...
So I have parsers and want to use the first that does return a non-null value. How would I do that most elegantly?
return parsers.map { it.parse(content) }.firstOrNull { it != null }
would map all (million?) parsers before picking the first.
return parsers.firstOrNull { it.parse(content) != null }?.parse(content)
would run the (expensive?) parse() once again.
I know I can
for (parser in parsers) {
val result = parser.parse(content)
if (result != null) {
return result
}
}
return null
parsers.forEach { it.parse(content)?.run { return this } }
return null
is the shortest I can get but it's not nice to read.
I'm pretty sure there is a shortcut here that I don't see.
Use a sequence. It makes your computation lazy, so that you will only compute parse as many times as you need.
return parsers.asSequence()
.map { it.parse(content) }
.find { it != null }
As an alternative to the overhead of a Sequence, or mapping lots of values unnecessarily, you could use an extension method such as:
inline fun <T, R> List<T>.firstMappedNotNull(transform: (T) -> R): R? {
for (e in this)
return transform(e) ?: continue
return null
}
This uses the minimum of mapping function calls and temporary objects. It's necessarily written in an imperative way, but it's quite short, and makes your own code short, clear, and functional.
(This version returns null if the list was empty or every mapping returned null. You could of course change the signature and last line to throw an exception instead.)
It's a shame this function isn't already in the standard library. But it's easy to add your own!
Also, you can use the following code:
parsers.asSequence()
.mapNotNull { it.parse(content) }
.first()