It’s quite easy to trigger a NullPointerException in Kotlin. Let’s look at a small snippet:
import java.util.concurrent.atomic.AtomicReference
func main() {
val foo: AtomicReference<Int> = AtomicReference(42)
foo.set(null) // it compiles!!!
println("The answer is " + foo.get().toDouble())
}
Credit to Uberto Barbini for the code snippet and tweet illustrating this problem.
So what’s happening here? Shouldn’t the Kotlin type system prevent this issue?
As soon as you interact with Java code, null restrictions don't have the same rules. We can see that if we wrap the Java class in Kotlin, we won’t have the same issue.
import java.util.concurrent.atomic.AtomicReference
class MyAtomicReference<T>(initialValue: T) {
private val javaAtomicRef = AtomicReference(initialValue)
fun get(): T = javaAtomicRef.get()
fun set(newValue: T) = javaAtomicRef.set(newValue)
}
val foo: MyAtomicReference<Int> = MyAtomicReference(42)
foo.set(null) // does not compile!!!
println("The answer is " + foo.get().toDouble())
Why do we face this problem in the first place? In Java everything can be null, but why do we need that to bleed over?
The first problem is that Kotlin can’t know if a value coming from Java code can be null. If we assume that all of them can be null then you’d be forced to deal with that possibility on cases where it doesn’t happen and it’d be annoying.
Can we assume the opposite, that no values coming from Java are null? We can, because Kotlin won’t stop you from doing null-checks or anything else you would do to safeguard your code.
But do we really have to face this problem when a Java class / interface has a generic? Come on, there we get to specify if we want a `String` or a `String?`…
Unfortunately that doesn’t work for all cases.
Let’s go over a concrete Java interface I just made up:
import java.util.function.Predicate
interface Filtered<T> {
void set(T t); // T should never be null
void filter(Predicate<T> f);
T get() // T can be null
}
If I instantiated that interface with `String?` as `T`, then I can pass null to the `set` function, which is a lie.
If I instantiated that interface with `String` as `T`, then we’re thinking that what is returned from `get` is never null, which is also a lie.
No way to be honest this time! Because we lack information to do so.
So the language designers stuck with the ones that give the user the most flexibility.
In any case make sure to browse the official Kotlin documentation. It tends to be pretty good.
And my final advice to you is:
wrap Java code
make sure it’s properly tested
Hopefully that allows avoiding those nasty NullPointerExceptions in production.