While Kotlin comes along with all its nice null-safety features like nullity encoded in the type system, smart casts, safe calls and the elvis operator, there are still situations where you might encounter a
NullPointerException (NPE), some of which are pretty obvious, while others are very subtle and can give you real headaches. The goal is to prepare you, so you have a better guess at what might be the source of your current NPE.
The not-null assertion operator (!!)
The most obvious one, and actually the only one in pure Kotlin I could come up with, is forcing Kotlin to treat a nullable as if it was not.
The double exclamation mark (a.k.a. the not-null assertion operator) tells Kotlin to treat the value as non-nullable and if it actually is
null, throws an NPE.
There are two situation to use this:
You know more than the compiler
This would for example happen if you are working with a container. Getting something out of a container could usually return
null, as the container might not contain the requested item. But sometimes you control every part of that container, so you can be completely sure, the item is there. In that case the operator can be used safely.
You actually want an NPE if the value turns out to be null
You might be at a location in the code where you need a value and a
null should really not appear there. You also can’t react to
null in a reasonable way, so you force the NPE for some caller to handle the error.
Reading and writing platform types
Most NPEs will be results of interfacing the platform (e.g. JVM, JS, Android). While Kotlin supports a lot of annotations to determine whether parameters, fields or return types are nullable, this requires the used library to make use of these. If the nullity is not stated, Kotlin does not make any assumptions about it and uses so called platform types. In compiler output they look like
Type! (notice the single exclamation mark). It is not possible to create variables in Kotlin with a platform type other than capturing the result of a platform function in a variable with automatically deduced type (i.e. without explicitly stating a type).
In the following examples I am talking about Java functions, but the same behaviour can be assumed for other platforms.
When calling a Java function returning a platform type, Kotlin will trust us, when we assign the value to a variable:
The danger in the first assignment comes from the fact, that it is not obvious, that an NPE might be thrown. Therefore I prefer to do a forced conversion in such cases:
When calling a Java function taking a platform type, Kotlin will also trust us on whatever we pass in.
Sadly we don’t have any way to make it more obvious, that the second version might throw an NPE.
Calling a Java function passing in the result of another Java function
Now this is a really subtle one. Especcially, because this one can throw an NPE even though the Java code would deal with a
null just fine.
Why does this happen? Kotlin tries to prevent propagation of undesired
null values. In Java you might face the problem, that a
null occurred at some location where it should not have. Yet it is not checked our accessed there. Instead, it is passed to one function, then to another. Several levels down the call stack we then access it without checking and BOOM! we have an NPE at a location not even remotely close to the location where the faulty
null came to life. Kotlin perfectly prevents that in itself, because the type always carries the nullity information. When interfacing with Java it atleast tries to help us by preventing the propagation of
null, how do we tell that to Kotlin? We need to capture the result of
getIntFromJava in a temporary value of which we state the nullity explicitly: