Kotlin — combating non-null assertions (!!)

Igor Wojda 🤖
4 min readJun 11, 2017

--

I have been reviewing few Kotlin projects recently and I was greatly disturbed by the fact that developers use to much of non-null assertions (!!). This operator should be used very rarely, because it is a sign of potential NullPointerException. Each time you see !! in Kotlin code BIG yellow warning sign should popup in your head . Just to be clear I am not saying not use non-null assertions at all, but rather make 100% sure that you are using this operator correctly and even if you think you are sure then ask on Kotlin slack channel if you really are. There is very limited proper usages for this operator. By intention double exclamation marks means “double warning” or “hey watch out here!”, but some developers treat it just as another operator. Let’s dive into examples and refactor the code by removing unnecessary non-null assertion operators.

Warning 1

Never use code like this because using multiple non-null assertion you increase chance for potential NullPointerException. If you get an exception in this line, you won’t be able to tell whether company or address was null.

person.company!!.address!!.country

Safe call operator will keep the code safe and make sure that NullPointerException will never happen.

person.company?.address?.country

If you are really sure that those variables will not hold null values simply declare them as non-nullable to remove need for safe call operator.

Warning 2

This is an example is related to collection filtering.

class Foo(val name: String)val list = listOf(Foo("Big"), null, Foo("Small")) //Inferred typed List<Foo?>
list.filter { it != null }
.map { it!!.name.toUpperCase() }

Code works fine, at least for now. When you decide to change filter criteria at some point in future your code may crash. We could use safe call operator here same as in previous example, but filterNotNull method will be better solution.

class Foo(val name: String)val list = listOf(Foo("Big"), null, Foo("Small")) //Inferred typed List<Foo?>
list.filterNotNull()
.map { it.name.toUpperCase() }

filterNotNull method removes nulls and casts nullable type Foo? to non-nullable type Foo. Now it is of type Foo and non-null assertion is not required anymore.

Warning 3

This is an example of a class used to store data loaded from the server. Nothing fancy we parse JSON and put a data to a class.

class ProfileData {

var name: String? = null
var thumbnail
: Image? = null

val imageUrl
: String
get() = thumbnail!!.url
}

Let’s consider two scenarios here assuming we want to return non-nullable imageUrl, because we want to display it in UI.

If thumbnail property can be null then defining it as nullable and using non-null assertion operator will result in application crash at some point. To fix it we can use safe call operator combined with elvis operator and return a default value.

class ProfileData {

var name: String? = null
var thumbnail
: Image2? = null

val imageUrl
: String
get() = thumbnail?.url ?: ""
}

If the thumbnail can’t be null then we can simply use lateinit modifier together with non-nullable data type.

class ProfileData {

lateinit var name: String
lateinit var thumbnail: Image

val imageUrl: String
get() = thumbnail.url
}

Warning 4

This is a little bit extreme, but it comes from real project. I was really surprised how creative some (Java) programmers can be :-) I could say a lot about this code…

open class BasePresenter<V> {
private var weakRef: WeakReference<V>? = null

val view
: V?
get() = if (weakRef == null) null else weakRef!!.get()

val isViewAttached: Boolean
get() = weakRef!= null && weakRef!!.get() != null
}

It’s not a time pointing fingers, but finding solutions, so we can make this code a little bit safer and simpler with a single safe call operator and a little bit of refactoring.

open class BasePresenter<V> {
private var weakRef: WeakReference<V>? = null

val view
: V?
get() = weakRef?.get()

val isViewAttached: Boolean
get() = (view != null)
}

In fact I have even proposed intention for this to Kotlin plugin, so we will not see code like this in the future (grab it if you like).

Warning 5

proposed by: Jean-Michel Fayard

This example comes from Android platform where we use adapter as data source for RecyclerView.

var recyclerView: RecyclerView? = null
val adapter : Adapter? = null
fun onCreate() {setContentView(...)
recyclerView = ....
adapter = createAdapter()
recyclerView!!.adapter = adapter!!
}

To fix this code we can combine bindView delegated property (kotterknife library) and lazy delegate (Kotlin stdlib).

val recyclerView: RecyclerView by bindView(R.id.recycler)val adapter : Adapter by lazy {
createAdapter()
}
fun onCreate() {
setContentView(...)
reyclerview.adapter = adapter
}

Updating the code gives us a few additional benefits besides safety. We can make our code more expressive by using read-only variable and perform variable declaration & initialization in a single line.

Summary

Each time you use non-null assertion you are saying to Kotlin compiler “I am 100% sure that this will not be null” and the reality is that in most of the cases there are better and safer ways solutions to achieve the same result.

I hope this post gave you deeper understanding when not to use non-null assertion and BIG yellow warning sign will appear in your head every time you’ll see those two characters (!!) in the code.

👉 Follow me on twitter to stay tuned.

Bonus: Stackoverflow post on dealing with null safety

If you liked this article please click the 💚, so other people can read it too. I would love to hear your thoughts in the comment section. Happy coding!

--

--

Igor Wojda 🤖

👉Android Developer Advocate at Vonage 👉Author of “Android Development with Kotlin” book 👉Follow me on twitter to learn more https://twitter.com/igorwojda