Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

requireNotNull vs sure operator !! in Kotlin

Tags:

kotlin

codacy

We have a Kotlin based application and recently we added third party code quality tools (Detekt in Codacy). However, we started facing UnsafeCallOnNullableType errors. We found that approach viable to use is to add requireNotNull checks on all parameter which maybe null. Currently, we are using sure operator (!!)

Do we have any specific reason or convention to chose one over the other. As far as I see, both will throw an Exception and will block the execution flow, except one will throw IllegalArgumentException while the other will throw NullPointerException.

like image 791
ashu Avatar asked Oct 09 '18 09:10

ashu


People also ask

When would you use Elvis operator in Kotlin?

Elvis operator (?:) is used to return the not null value even the conditional expression is null. It is also used to check the null safety of values. In some cases, we can declare a variable which can hold a null reference.

How do you ensure null safety in Kotlin?

Kotlin has a safe call operator (?.) to handle null references. This operator executes any action only when the reference has a non-null value. Otherwise, it returns a null value. The safe call operator combines a null check along with a method call in a single expression.

What does ?: Mean in Kotlin?

This is a binary expression that returns the first operand when the expression value is True and it returns the second operand when the expression value is False. Generally, the Elvis operator is denoted using "?:", the syntax looks like − First operand ?: Second operand.

How do I check if an object is null in Kotlin?

You can use the "?. let" operator in Kotlin to check if the value of a variable is NULL. It can only be used when we are sure that we are refereeing to a non-NULL able value.


2 Answers

requireNotNull, assuming you're referring to Objects#requireNonNull, is a Java method that is equivalent to !!, but with a different exception.

You didn't add any code, so it's slightly hard to help you debug. You mentioned third party code quality tools, but not which. I randomly stumbled over this GH issue that matches the error you're having. It's also the only thing I can find that would at any point use that exact error. I might have missed some, but it's the one that covers the top Google hits, so I'm going to go off that.

If you are using Detekt, this is a reported bug. Using !! is even suggested by IntelliJ.

However, you can do it another way.

Yes, using Objects#requireNonNull is one option. There is a second one though, and that's using the null-safe operator, as m0skit0 mentioned.

The reason this works is because if anything called is null, the final result is null. I.e. this:

instance.nonNullType.nullable?.nullableChild?.someOtherNullableChild

If any of the nullable ones are null, the final result is null, and none of the others are called.

Now, considering this is likely a bug in Detect, this seems like the easiest workaround for now:

whatever.calls.you?.make?.to?.the?.database ?: throw NullPointerException("Something is null");

It also keeps the variable non-null, which means you don't need null-safe calls later. The elvis operator checks if anything is null, then throws an exception. Alternatively, you can just use Objects#requireNotNull:

Objects.requireNonNull(whatever.calls.you.make.to.the.database)

If you really need to validate every single step, you'll just need to keep null checks everywhere

TL;DR:

!! and requireNotNull are effectively identical in how they work, except requireNotNull is a method call and !! compiles to an if-statement:

if(whatever == null) {
    Intrinsics.throwNpe();
}

The reason !! triggers UnsafeCallOnNullableType is because of a (probable) bug in Detekt. Both of the options are syntactic sugar for the same thing, though: if the variable is null, throw an NPE.

like image 145
Zoe stands with Ukraine Avatar answered Oct 12 '22 03:10

Zoe stands with Ukraine


As you mentioned, requireNotNull() throws IllegalArgumentException and !! throws NullPointerException. That could be helpful if you want to differentiate between defensive code added by your devs versus undefended code (by using !! is isn't immediately obvious).

However, the bigger benefit of using requireNotNull() is using the function that takes the lazyMessage argument. This way your devs can add more meaningful messages to the exception, which could help in debugging

like image 29
Ed Ballot Avatar answered Oct 12 '22 03:10

Ed Ballot