Null safety
In Kotlin, the nullability of a variable is an integral part of its type.
Fortunately, it is quickly determined with a simple ?
.
The infamous NullPointerException
is probably the most common error message that Java programs produce at runtime.
It is no coincidence that Tony Hoare, the “inventor” of the “zero reference”, describes it as his “trillion-dollar mistake”.
While in Java annotations like @NotNull
only slightly improve the control over the nullability of references, it is an integral part of the Kotlin language.
There are real keywords and operators dealing with nullability, and the compiler also provides corresponding checks.
Declaring nullability
In fact, in Kotlin, for each declaration of a variable, one has to indicate whether it can ever become null
.
What initially sounds like cumbersome extra work, is in fact none at all.
Kotlin makes it possible to specify the nullability of a variable very simply and briefly:
Appending a ?
to the type of a variable declares it as potentially null
while omitting the ?
declares it as “never null
” (@NotNull).
var nullable : String? = "Foo"
var notNullable : String = "Bar"
nullable = null // OK
notNullable = null // compile-time error (instead of a NullPointerException at runtime)
val i = notNullable.length // OK
val j = nullable.length // compile-time error: nullable is/could be null at this point
if (nullable != null) // check for null
{
val k = nullable.length // OK! The compiler recognizes that nullable can not be null at this point, due to the outer if
}
Safe calls
With the so-called safe calls Kotlin offers a very practical syntax in connection with possible null
references:
val fn = person?.firstName
What looks like an ordinary access to the firstName
property of the object referenced by person
differs only in the inserted ?
.
This means that person
may also be null
.
If this is actually the case, the access to firstName
is suppressed (it would lead to a NullPointerException
anyway).
Rather, the entire expression yields null
, which is then assigned to fn
(which, consequently, is of type String?
, by the way).
On the other hand, if person
is not null
the property firstName
will be accessed and its value will be assigned to fn
.
If one does not want to assign null
to fn
in case that person
is null
, but rather a different special value, there is also a syntax for this:
val fn = person?.firstName ?: "Unknown first name"
So you attach the ?:
operator to the safe call, followed by the value that it should return if the reference in question is null
.
Of course, all this not only works when accessing properties, but also for function calls:
person?.saveToDatabase()
This will save the person
to the database only if the reference is not null
, otherwise nothing will happen at all - in particular no NullPointerException
will be raised.