how to avoid null check - intellij-idea

I have a repository class like this:
interface TodosRepository : CrudRepository<Todo, Long> {
fun findByUid(uid: String): Todo?
}
and a method that can mark this todo as done:
fun markAsDone(uid: String): ResponseEntity<String> {
var todo = todosRepository.findByUid(uid)
if(todo == null){
return ResponseEntity("Not found", HttpStatus.NOT_FOUND)
}
todo.status = 1
todosRepository.save(todo)
return ResponseEntity.ok("Saved")
}
IntelliJ ask me to replace the todo == null with an elvis operator:
fun markAsDone(uid: String): ResponseEntity<String> {
var todo: Todo? = todosRepository.findByUid(uid) ?: return ResponseEntity("Not found", HttpStatus.NOT_FOUND)
todo.status = 1
todosRepository.save(todo)
but then, it asks me to use the null check when setting the status to 1 with todo?.status = 1
the thing is that I think it shouldn't ask me, because at that point, I'm pretty sure that todo is not null anymore.
Is there any workaround or I maybe misunderstood something on Kotlin?

I believe you could make the variable non-nullable to fix this. Probably also a val.
val todo: Todo = todosRepository.findByUid(uid) ?: return ResponseEntity("Not found", HttpStatus.NOT_FOUND)
Edit: omitting the return type should also work to infer the non-nullable Todo type.
The automatic change that IntelliJ suggested would've worked smoothly if you didn't have an explicit type; it seems like it chose to keep it unmodified instead of changing it to non-nullable, which somewhat defeats the purpose of the hint.
val todo = todosRepository.findByUid(uid) ?: return ResponseEntity("Not found", HttpStatus.NOT_FOUND)

Related

Kotlin idiomatic way for extracting logic that gets executed when a value is null

I have something like this in Kotlin, repeated in several places (and please bear in mind that I'm relatively new to the language and I'm still figuring out what's the best/ more idiomatic way to do things):
class SomeClass {
fun someMethod(c: Context) {
val id: String? = c.someValue?.someId
if(id == null) {
return someResult("some message")
}
doSomething(id)
}
}
I would like to find an idiomatic way of extracting
if(id == null) {
return someResult("some message")
}
and still be able to use the value of id without having to help the compiler determining its value is not null. How can I do this idiomatically in Kotlin?
You can use kotlin elvis operator it works the same as if(id == null) {...} :
class SomeClass {
fun someMethod(c: Context) {
val id: String = c.someValue?.someId ?: return someResult("some message")
doSomething(id)
}
}

kotlin: If value is null then exit, else use that value as not nullable

Essentially this is in the title. I have a value that could be null. If it is, I just want to exit with a message. If it's not null, then there's a whole slew of work I need to do with this value.
I've found similar, but not quite this exact situation. And it's the subtle difference that's driving me nuts. Here is my code in java:
if (value == null) {
print("error!");
return;
}
print(value);
doFunStuff(value);
etc(value);
All those methods using value require it to be non-null.
But I'm having a difficult time figuring this out in kotlin. With everything I try, the compiler still insists that value is still nullable and refuses to use it in the functions.
What is the kotlin way of doing this very common code flow?
If your methods truly have non-null parameters, the Kotlin compiler should be smart enough to do a smart cast to Object from Object?.
fun yourMethod(value: Object?) {
if (value == null) {
print("error!")
return
}
print(value) // Smart cast happens here
doFunStuff(value)
etc(value)
}
fun print(value: Object) {
// Implementation
}
fun doFunStuff(value: Object) {
// Implementation
}
fun etc(value: Object) {
// Implementation
}
But you can also force the conversion by using the !! operator (though in this case the compiler will tell you it's not necessary):
fun yourMethod(value: Object?) {
if (value == null) {
print("error!")
return
}
val nonNullValue = value!!
print(nonNullValue)
doFunStuff(nonNullValue)
etc(nonNullValue)
}
fun print(value: Object) {
// Implementation
}
fun doFunStuff(value: Object) {
// Implementation
}
fun etc(value: Object) {
// Implementation
}
If your value is a local variable or a function parameter, you won't have this problem, because the compiler will smart-cast it to not-null.
So, I'm assuming value in this case is a member property.
Option 1 is to copy it to a local variable to use in the function:
val value = value
if (value == null) {
print("error!")
return
}
print(value)
doFunStuff(value)
etc(value)
Option 2 is to use the let or also scope functions to do the same thing, but this might not be a good option here because so much code would become nested. This is more useful when you're only calling one or two functions with the object, in which case, you wouldn't even have to name it (just call it it).
value.let { value ->
if (value == null) {
print("error!")
return
}
print(value)
doFunStuff(value)
etc(value)
}
If your entire function works with this one property, you can avoid the nesting problem like this, if you don't mind it returning something besides Unit:
fun foo() = value.also { value ->
if (value == null) {
print("error!")
return
}
print(value)
doFunStuff(value)
etc(value)
}
Option 3 is to assert non-null every time you use it, but this is very ugly. This is only safe if you know the property is only ever accessed from the same thread this function is ever called on.
if (value == null) {
print("error!")
return
}
print(value!!)
doFunStuff(value!!)
etc(value!!)
Expanding on #Mehul's answer, this would only run the code in the let if the value was not null. If null, you could run the outside process and return from it.
value?.let { nonNullValue ->
print(nonNullValue);
doFunStuff(nonNullValue);
etc(nonNullValue);
}?: run { print("error!") ; return }
That said, since you are no longer needing the return to abort the function if null, you could simply do this and further clean it up replacing the lambda.
value?.let {
print(it);
doFunStuff(it);
etc(it);
}?: print("error!")
Well, have you already tried something like this and this is not what you expect?
value?.let { nonNullValue ->
print(nonNullValue);
doFunStuff(nonNullValue);
etc(nonNullValue);
}
basically the code inside let block will run only if the value isn't null.

How can I let the Kotlin compiler know I already checked for null inside a function?

Basically I have a function that does some stuff but specifically it checks if two values I'm passing are null. This function is called from various places to make sure those two values are not null. Kotlin is complaining later that I'm not checking for null. Is there a way I can do this so that Kotlin already knows that I am checking for null without using !!?
Here is a simple example:
private fun stuff() {
var possibleNull: String? = "test"
if (testNull(possibleNull)) {
mustPassNonNull(possibleNull)
}
}
private fun mustPassNonNull(possibleNull: String) {
//use value that isn't null
}
private fun testNull(possibleNull: String?): Boolean {
return possibleNull != null
}
Basically testNull is only true if possibleNull is not null and that check is on an if right before calling mustPassNonNull so can I let Kotlin know I'm already checking that? without using !! of course.
Thanks.
It is possible with the use of contracts. Currently in experimental in Kotlin 1.3.
It is possible to declare contracts for your own functions, but this feature is experimental, as the current syntax is in a state of early prototype and will most probably be changed. Also, please note, that currently the Kotlin compiler does not verify contracts, so it's a programmer's responsibility to write correct and sound contracts. -kotlinlang.org
#ExperimentalContracts
fun stuff() {
var possibleNull: String? = "test"
if (testNull(possibleNull)) {
mustPassNonNull(possibleNull)
}
}
fun mustPassNonNull(possibleNull: String) {
//use value that isn't null
}
#ExperimentalContracts
fun testNull(possibleNull: String?): Boolean {
contract{
returns(true) implies (possibleNull is String)
}
return possibleNull != null
}
Articles I referenced:
https://kotlinlang.org/docs/reference/whatsnew13.html
https://blog.kotlin-academy.com/understanding-kotlin-contracts-f255ded41ef2
It seems like a simple let situation
private fun stuff() {
var possibleNull: String? = "test"
possibleNull?.let { mustPassNonNull(it) }
}
This way mustPassNonNull will know that it isn't null :)
Also, if you need to do more than just check for nullability you could do:
possibleNull
?.takeIf { /* it's not null here anymore, add any checks you need */}
?.let { /* both non-null and checked for whatever you need */}

Kotlin: Null check in if block

I started to learn Kotlin recently. One thing I can't get my head around is the null check blocks. The following statement is considered unsafe, and the compiler won't allow you to compile this.
var testVar: String? = null;
// if (testVar != null )
{
// Doing some work....
println(testVar.length)
}
But when you uncomment the if line, everything works. This seems great.
But what if // Doing some work.... is computationally expensive and another thread changes the value of testVar to null while this thread is in // Doing some work line? In this scenario:
Does the program throw a NullPointerException?
OR:
Does the bytecode cache the value of testVar and use the cached value inside the if block?
In your initial example, is your var local to a function? For example:
fun doStuff() {
var testVar: String? = null
if (testVar != null) {
println(testVar.length)
}
}
In this case, no other scope has reference to testVar so nothing else can change it. However, if the var is a class property, i.e.
class MyClass {
var testVar: String? = null
fun doStuff() {
if (testVar != null) {
println(testVar.length)
}
}
}
This will fail to compile as testVar could have been set to null by another thread in between the check and the usage.
Going further, if you try to be tricky:
fun doStuff() {
var testVar: String? = null
fun trickyFunction() {
testVar = null
}
if (testVar != null) {
trickyFunction()
println(testVar.length)
}
}
The compiler will fail as your variable is captured by a changing closure. So in general, if you are able to use the variable via a smart-cast to non-null, you should not have to worry about any potential for NPEs.
For the second scenario (var properties) it is preferable to rely on .let to capture an immutable reference to the current value, i.e.
testVar?.let { capturedTestVar ->
println(capturedTestVar.length)
}

Best way to null check in Kotlin?

Should I use double =, or triple =?
if(a === null) {
//do something
}
or
if(a == null) {
//do something
}
Similarly for 'not equals':
if(a !== null) {
//do something
}
or
if(a != null) {
//do something
}
A structural equality a == b is translated to
a?.equals(b) ?: (b === null)
Therefore when comparing to null, the structural equality a == null is translated to a referential equality a === null.
According to the docs, there is no point in optimizing your code, so you can use a == null and a != null
Note that if the variable is a mutable property, you won't be able to smart cast it to its non-nullable type inside the if statement (because the value might have been modified by another thread) and you'd have to use the safe call operator with let instead.
Safe call operator ?.
a?.let {
// not null do something
println(it)
println("not null")
}
You can use it in combination with the Elvis operator.
Elvis operator ?: (I'm guessing because the interrogation mark looks like Elvis' hair)
a ?: println("null")
And if you want to run a block of code
a ?: run {
println("null")
println("The King has left the building")
}
Combining the two
a?.let {
println("not null")
println("Wop-bop-a-loom-a-boom-bam-boom")
} ?: run {
println("null")
println("When things go null, don't go with them")
}
Kotlin ways of handling null
Secure Access Operation
val dialog : Dialog? = Dialog()
dialog?.dismiss() // if the dialog will be null,the dismiss call will be omitted
Let function
user?.let {
//Work with non-null user
handleNonNullUser(user)
}
Early exit
fun handleUser(user : User?) {
user ?: return //exit the function if user is null
//Now the compiler knows user is non-null
}
Immutable shadows
var user : User? = null
fun handleUser() {
val user = user ?: return //Return if null, otherwise create immutable shadow
//Work with a local, non-null variable named user
}
Default value
fun getUserName(): String {
//If our nullable reference is not null, use it, otherwise use non-null value
return userName ?: "Anonymous"
}
Use val instead of var
val is read-only, var is mutable. It’s recommended to use as many read-only properties as you can, they are thread-safe.
Use lateinit
Sometimes you can’t use immutable properties. For example, it happens on Android when some property is initialized in onCreate() call. For these situations, Kotlin has a language feature called lateinit.
private lateinit var mAdapter: RecyclerAdapter<Transaction>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mAdapter = RecyclerAdapter(R.layout.item_transaction)
}
fun updateTransactions() {
mAdapter.notifyDataSetChanged()
}
Both approaches generate the same bytecode so you can choose whatever you prefer.
Addition to #Benito Bertoli,
the combination is actually unlike if-else
"test" ?. let {
println ( "1. it=$it" )
} ?: let {
println ( "2. it is null!" )
}
The result is:
1. it=test
But if:
"test" ?. let {
println ( "1. it=$it" )
null // finally returns null
} ?: let {
println ( "2. it is null!" )
}
The result is:
1. it=test
2. it is null!
Also, if use elvis first:
null ?: let {
println ( "1. it is null!" )
} ?. let {
println ( "2. it=$it" )
}
The result is:
1. it is null!
2. it=kotlin.Unit
Check useful methods out, it could be useful:
/**
* Performs [R] when [T] is not null. Block [R] will have context of [T]
*/
inline fun <T : Any, R> ifNotNull(input: T?, callback: (T) -> R): R? {
return input?.let(callback)
}
/**
* Checking if [T] is not `null` and if its function completes or satisfies to some condition.
*/
inline fun <T: Any> T?.isNotNullAndSatisfies(check: T.() -> Boolean?): Boolean{
return ifNotNull(this) { it.run(check) } ?: false
}
Below is possible example how to use those functions:
var s: String? = null
// ...
if (s.isNotNullAndSatisfies{ isEmpty() }{
// do something
}
I want to respond to answers of #Benito Bertoli and #BingLi224 and provide imho correct solution.
Problem is with using let, because result of let is it's last expression. You just want to pass the same thing as is passed into it, so also is a better solution. At the same time, after using elvis operator, let is impossible to use, because there is no object to call extension function to so I am using run (functional version). More on that in the scope functions official documentation
Another downside of this compared to using if/when is not being able to use this as an expression so I wouldn't recommend using it :-)
Final code:
"test"?.also {
println("1. it=$it")
} ?: run {
println("2. it is null!")
}
"test"?.also {
println("1. it=$it")
null
} ?: run {
println("2. it is null!")
}
null?.also {
println("1. it is null!")
} ?: run {
println("2. it is null")
}
null?.also {
println("1. it is null!")
null
} ?: run {
println("2. it is null")
}
And output:
1. it=test
1. it=test
2. it is null
2. it is null