Null Safety

    One of the most common pitfalls in many programming languages, including Java, is that accessing a member of a null reference will result in a null reference exception. In Java this would be the equivalent of a NullPointerException or NPE for short.

    Kotlin’s type system is aimed to eliminate NullPointerException‘s from our code. The only possible causes of NPE’s may be:

    • An explicit call to throw NullPointerException();
    • Usage of the !! operator that is described below;
    • Some data inconsistency with regard to initialization, such as when:
    • Java interoperation:
      • Attempts to access a member on a null reference of a ;
      • Generic types used for Java interoperation with incorrect nullability, e.g. a piece of Java code might add null into a Kotlin MutableList<String>, meaning that MutableList<String?> should be used for working with it;
      • Other issues caused by external Java code.

    In Kotlin, the type system distinguishes between references that can hold null (nullable references) and those that can not (non-null references). For example, a regular variable of type String can not hold null:

    To allow nulls, we can declare a variable as nullable string, written String?:

    1. fun main() {
    2. var b: String? = "abc" // can be set null
    3. b = null // ok
    4. print(b)
    5. //sampleEnd
    6. }

    Now, if you call a method or access a property on a, it’s guaranteed not to cause an NPE, so you can safely say:

    1. val l = a.length

    But if you want to access the same property on b, that would not be safe, and the compiler reports an error:

    1. val l = b.length // error: variable 'b' can be null

    But we still need to access that property, right? There are a few ways of doing that.

    Checking for null in conditions

    The compiler tracks the information about the check you performed, and allows the call to length inside the if. More complex conditions are supported as well:

    Note that this only works where b is immutable (i.e. a local variable which is not modified between the check and the usage or a member val which has a backing field and is not overridable), because otherwise it might happen that b changes to null after the check.

    Your second option is the safe call operator, written ?.:

    1. fun main() {
    2. //sampleStart
    3. val a = "Kotlin"
    4. val b: String? = null
    5. println(b?.length)
    6. println(a?.length) // Unnecessary safe call
    7. //sampleEnd
    8. }

    This returns b.length if b is not null, and null otherwise. The type of this expression is Int?.

    Safe calls are useful in chains. For example, if Bob, an Employee, may be assigned to a Department (or not), that in turn may have another Employee as a department head, then to obtain the name of Bob’s department head (if any), we write the following:

    1. bob?.department?.head?.name

    Such a chain returns null if any of the properties in it is null.

    To perform a certain operation only for non-null values, you can use the safe call operator together with :

    1. //sampleStart
    2. val listWithNulls: List<String?> = listOf("Kotlin", null)
    3. for (item in listWithNulls) {
    4. item?.let { println(it) } // prints Kotlin and ignores null
    5. //sampleEnd
    6. }
    1. // If either `person` or `person.department` is null, the function is not called:
    2. person?.department?.head = managersPool.getManager()

    Elvis Operator

    When we have a nullable reference b, we can say “if b is not null, use it, otherwise use some non-null value”:

    Along with the complete if-expression, this can be expressed with the Elvis operator, written ?::

    1. val l = b?.length ?: -1

    If the expression to the left of ?: is not null, the elvis operator returns it, otherwise it returns the expression to the right. Note that the right-hand side expression is evaluated only if the left-hand side is null.

    Note that, since throw and return are expressions in Kotlin, they can also be used on the right hand side of the elvis operator. This can be very handy, for example, for checking function arguments:

    1. fun foo(node: Node): String? {
    2. val parent = node.getParent() ?: return null
    3. val name = node.getName() ?: throw IllegalArgumentException("name expected")
    4. // ...
    5. }

    The third option is for NPE-lovers: the not-null assertion operator (!!) converts any value to a non-null type and throws an exception if the value is null. We can write b!!, and this will return a non-null value of b (e.g., a String in our example) or throw an NPE if b is null:

    1. val l = b!!.length

    Thus, if you want an NPE, you can have it, but you have to ask for it explicitly, and it does not appear out of the blue.

    Safe Casts

    Regular casts may result into a ClassCastException if the object is not of the target type. Another option is to use safe casts that return null if the attempt was not successful: