Drako's Developer Blog

My thoughts on programming

NPEs in Kotlin

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.

Return types

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:

Parameters

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.

So assuming passIntToJava supports 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:


Leave a Reply

Your email address will not be published. Required fields are marked *

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close