
Nullability in Kotlin
This is a chapter from the book Kotlin Essentials. You can find it on LeanPub or Amazon. It is also available as a course.
Kotlin started as a remedy to Java problems, and the biggest problem in Java is nullability. In Java, like in many other languages, every variable is nullable, so it might have the null value. Every call on a null value leads to the famous NullPointerException (NPE). This is the #1 exception in most Java projects0. It is so common that it is often referred to as “the billion dollar mistake” after the famous speech by Sir Charles Antony Richard Hoare, where he said: “I call it my billion-dollar mistake. It was the invention of the null reference in 1965… This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years”.
One of Kotlin's priorities was to solve this problem finally, and it achieved this perfectly. The mechanisms introduced in Kotlin are so effective that seeing NullPointerException thrown from Kotlin code is extremely rare. The null value stopped being a problem, and Kotlin developers are no longer scared of it. It has become our friend.
So, how does nullability work in Kotlin? Everything is based on a few rules:
- Every property needs to have an explicit value. There is no such thing as an implicit
nullvalue.
- A regular type does not accept the
nullvalue.
- To specify a nullable type, you need to end a regular type with a question mark (
?).
- Nullable values cannot be used directly. They must be used safely or cast first (using one of the tools presented later in this chapter).
Thanks to all these mechanisms, we always know what can be null and what cannot. We use nullability only when we need it - when there is a reason to. In such cases, users are forced to explicitly handle this nullability. In all other cases, there is no need to do this. This is a perfect solution, but good tools are needed to deal with nullability in a way that’s convenient for developers.
Kotlin supports a variety of ways of using a nullable value, including safe calls, not-null assertions, smart-casting, or the Elvis operator. Let's discuss these one by one.
Safe calls
The simplest way to call a method or a property on a nullable value is with a safe call, which is a question mark and a dot (?.) instead of just a regular dot (.). Safe calls work as follows:
- if a value is
null, it does nothing and returnsnull, - if a value is not
null, it works like a regular call.
Notice that the result of a safe call is always a nullable type because a safe call returns null when it is called on a null. This means that nullability propagates. If you need to find out the length of a user's name, calling user?.name.length will not compile. Even though name is not nullable, the result of user?.name is String?, so we need to use a safe call again: user?.name?.length.
Not-null assertion
When we don’t expect a null value, and we want to throw an exception if one occurs, we can use the not-null assertion !!.
This is not a very safe option because if we are wrong and a null value is where we don't expect it, this leads to a NullPointerException. Sometimes we want to throw an exception to ensure that there are no situations where null is used, but we generally prefer to throw a more meaningful exception4. For this, the most popular options are:
requireNotNull, which accepts a nullable value as an argument and throwsIllegalArgumentExceptionif this value is null. Otherwise, it returns this value as non-nullable.checkNotNull, which accepts a nullable value as an argument and throwsIllegalStateExceptionif this value is null. Otherwise, it returns this value as non-nullable.
Smart-casting
Smart-casting also works for nullability. Therefore, in the scope of a non-nullability check, a nullable type is cast to a non-nullable type.
Smart-casting also works when we use return or throw if a value is not null.
Smart-casting is quite smart and works in different cases, such as after && and || in logical expressions.
Smart-casting works in the code above thanks to a feature called contracts, which is explained in the book Advanced Kotlin.
The Elvis operator
The last special Kotlin feature that is used to support nullability is the Elvis operator ?:. Yes, it is a question mark and a colon. It is called the Elvis operator because it looks like Elvis Presley (with his characteristic hair), looking at us from behind a wall, so we can only see his hair and eyes.


It is placed between two values. If the value on the left side of the Elvis operator is not null, we use the nullable value that results from the Elvis operator. If the left side is null, then the right side is returned.
We can use the Elvis operator to provide a default value for nullable values.
Extensions on nullable types
Regular functions cannot be called on nullable variables. However, there is a special kind of function that can be defined such that it can be called on nullable variables3. Thanks to this, Kotlin stdlib defines the following functions that can be called on String?:
orEmptyreturns the value if it is notnull. Otherwise it returns an empty string.isNullOrEmptyreturnstrueif the value isnullor empty. Otherwise, it returnsfalse.isNullOrBlankreturnstrueif the value isnullor blank. Otherwise, it returnsfalse.
Kotlin stdlib also includes similar functions for nullable lists:
orEmptyreturns the value if it is notnull. Otherwise, it returns an empty list .isNullOrEmptyreturnstrue, returnstrueif the value isnullor empty. Otherwise, it returnsfalse.
These functions help us operate on nullable values.
null is our friend
Nullability was a source of pain in many languages like Java, where every object can be nullable. As a result, people started avoiding nullability. As a result, you can find suggestions like "Item 43. Return empty arrays or collections, not nulls" from Effective Java 2nd Edition by Joshua Bloch. Such practices make literally no sense in Kotlin, where we have a proper nullability system and should not be worried about null values. In Kotlin, we treat null as our friend, not as a mistake1. Consider the getUsers function. There is an essential difference between returning an empty list and null. An empty list should be interpreted as "the result is an empty list of users because none are available". The null result should be interpreted as "could not produce the result, and the list of users remains unknown". Forget about outdated practices regarding nullability. The null value is our friend in Kotlin2.
lateinit
There are situations where we want to keep a property type not nullable, and yet we cannot specify its value during object creation. Consider properties whose value is injected by a dependency injection framework, or consider properties that are created for every test in the setup phase. Making such properties nullable would lead to inconvenient usage: you would use a not-null assertion even though you know that the value cannot be null because it will surely be initialized before usage. For such situations, Kotlin creators introduced the lateinit property. Such properties have non-nullable types, and cannot be initialized during creation.

When we use a lateinit property, we must set its value before its first use. If we don't, the program throws an UninitializedPropertyAccessException at runtime.
You can always check if a property has been initialized using the isInitialized property on its reference. To reference a property, use two colons and a property name5.
Summary
Kotlin offers powerful nullability support that turns nullability from scary and tricky into useful and safe. This is supported by the type system, which separates what is nullable or not nullable. Variables that are nullable must be used safely; for this, we can use safe-calls, not-null assertions, smart-casting, or the Elvis operator. Now, let's finally move on to classes. We’ve used them many times already, but we finally have everything we need to describe them well.
Some research confirms this: for example, data collected by OverOps confirms that NullPointerException is the most common exception in 70% of production environments.
See the "Null is your friend, not a mistake" (link kt.academy/l/re-null) article by Roman Elizarov, current Project Lead for the Kotlin Programming Language.
There is more on using nullability in the book Effective Kotlin.
These are extension functions, which we will discuss in the chapter Extensions.
There is more about exceptions, IllegalArgumentException and IllegalStateException in the chapter Exceptions.
To reference a property from another object, we need to start with the object before we use :: and the property name. There is more about referencing properties in the Advanced Kotlin book.

