Use nullability in Kotlin¶

Before you begin¶

  • This codelab teaches you about nullability and the importance of null safety. Nullability is a concept commonly found in many programming languages. It refers to the ability of variables to have an absence of value. In Kotlin, nullability is intentionally treated to achieve null safety.

Prerequisites¶

  • Knowledge of Kotlin programming basics, including variables, accessing methods and properties from a variable and the println() and main() functions

  • Familiarity with Kotlin conditionals, including if/else statements and Boolean expressions

What you’ll learn¶

  • What null is.

  • The difference between nullable and non-nullable types.

  • What null safety is, its importance, and how Kotlin achieves null safety.

  • How to access methods and properties of nullable variables with the ?. safe call operator and !! non-null assertion operator.

  • How to perform null checks with if/else conditionals.

  • How to convert a nullable variable to a non-nullable type with if/else expressions.

  • How to provide a default value when a nullable variable is null with the if/else expression or the ?: Elvis operator.

What you’ll need¶

  • A web browser with access to Kotlin Playground

Use nullable variables¶

  • In Kotlin, you can use null to indicate that there’s no value associated with a certain variable. Example:

    fun main() {
        val favoriteActor = null
    }
    
  • In Kotlin, there’s a distinction between nullable and non-nullable types:

    • Nullable types are variables that can hold null.

    • Non-null types are variables that cannot hold null.

  • A type is only nullable if you explicitly let it hold null. As the error message says, the String data type is a non-nullable type, so you can’t reassign the variable to null.

    ../_images/unit2-pathway1-activity3-section2-c3bbad8de6afdbe9_1440.png
  • To declare nullable variables in Kotlin, you need to add a ? operator to the end of the type. For example, a String? type can hold either a string or null, whereas a String type can only hold a string. To declare a nullable variable, you need to explicitly add the nullable type. Without the nullable type, the Kotlin compiler infers that it’s a non-nullable type.

    fun main() {
        var number: Int? = 10
        println(number)
    
        number = null
        println(number)
    }
    

    Note

    While you should use nullable variables for variables that can carry null, you should use non-nullable variables for variables that can never carry null because the access of nullable variables requires more complex handling. You learn about various techniques to handle nullable variables in the next section.

Handle nullable variables¶

  • In this section, you learn how to access methods and properties of nullable variables.

  • The code below produces an error message:

    fun main() {
        var favoriteActor: String? = "Sandra Solulu"
        println(favoriteActor.length)
    }
    
    ../_images/unit2-pathway1-activity3-section3-5c5e60b58c31d162_1440.png
  • This error is a compile error, or compile-time error. A compile error happens when Kotlin isn’t able to compile the code due to a syntax error in your code.

  • Kotlin intentionally applies syntactic rules so that it can achieve null safety, which refers to a guarantee that no accidental calls are made on potentially null variables. This doesn’t mean that variables can’t be null. It means that if a member of a variable is accessed, the variable can’t be null.

  • This is critical because if there’s an attempt to access a member of a variable that’s null - known as a null reference - during the running of an app, the app crashes because the null variable doesn’t contain any property or method. This type of crash is known as a runtime error in which the error happens after the code has been compiled, and runs.

  • Due to the null safety nature of Kotlin, such runtime errors are prevented because the Kotlin compiler forces a null check for nullable types. A null check refers to a process of checking whether a variable could be null before it’s accessed and treated as a non-nullable type. If you wish to use a nullable value as its non-nullable type, you need to perform a null check explicitly. You’ll learn more about this later.

Use the ?. safe call operator¶

  • You can use the ?. safe call operator to access methods or properties of nullable variables.

    ../_images/unit2-pathway1-activity3-section3-a09b732437a133aa_1440.png
  • The ?. safe call operator allows safer access to nullable variables because the Kotlin compiler stops any attempt of member access to null references and returns null for the member accessed. Example:

    fun main() {
        var favoriteActor: String? = "Pigsy Pooh"
        println(favoriteActor?.length)
    }
    
  • When the below code is run, the output is null. The program doesn’t crash despite an attempt to access the length property of a null variable. The safe call expression simply returns null.

    fun main() {
        var favoriteActor: String? = null
        println(favoriteActor?.length)
    }
    

    Note

    You can also use the ?. safe call operators on non-nullable variables to access a method or property. While the Kotlin compiler won’t give any error for this, it’s unnecessary because the access of methods or properties for non-nullable variables is always safe.

Use the !! not-null assertion operator¶

  • You can also use the !! not-null assertion operator to access methods or properties of nullable variables.

    ../_images/unit2-pathway1-activity3-section3-1a6f269bfd700839_1440.png
  • If you use the !! not-null assertion, it means that you assert that the value of the variable isn’t null, regardless of whether it is or isn’t. You’re telling the compiler, I’m very very very sure that this value isn’t null, don’t complain about it during compile time.

  • Unlike ?. safe-call operators, the use of a !! not-null assertion operator may result in a NullPointerException error being thrown if the nullable variable is indeed null. Thus, it should be done only when the variable is always non-nullable or proper exception handling is set in place. When not handled, exceptions cause runtime errors. You learn about exception handling later.

  • Example:

    fun main() {
        var favoriteActor: String? = "Sandra Solulu"
        println(favoriteActor!!.length)
    }
    
  • In the above code, if the !! is removed, the compiler complains:

    Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type 'kotlin.String?'.
    
  • By adding !!, you’re telling the compiler that the value will never be null, and the compiler won’t complain during compile-time. However, if you were wrong and the value is indeed null, a NullPointerException error is thrown during run-time.

  • Example of code that will not cause any compile-time error, but will cause a NullPointerException run-time error:

    fun main() {
        var favoriteActor: String? = null
        println(favoriteActor!!.length)
    }
    

Use the if/else conditionals¶

  • To perform null checks, you can check that the nullable variable isn’t equal to null with the != comparison operator

    ../_images/unit2-pathway1-activity3-section3-326d68521327f229_1440.png
  • You can also check if a variable is null using ==

  • An if/else statement can be used together with a null check as follows:

    ../_images/unit2-pathway1-activity3-section3-4cca066cf405b09c_1440.png
  • The null check is more convenient to use with the if condition when there are multiple lines of code that use the nullable variable. In contrast, the ?. safe-call operator is more convenient for a single reference of the nullable variable.

  • Example:

    fun main() {
        var favoriteActor: String? = "Sandra Solulu"
    
        if (favoriteActor != null) {
            println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
        } else {
            println("You didn't input a name.")
        }
    }
    
  • You can also combine the null check with an if/else expression to convert a nullable variable to a non-nullable variable.

    ../_images/unit2-pathway1-activity3-section3-8bbf0c7e50163906_1440.png
  • Example:

    fun main() {
        var favoriteActor: String? = "Sandra Solulu"
    
        val lengthOfName = if (favoriteActor != null) {
            favoriteActor.length
        } else {
            0
        }
    
        println("The number of characters in your favorite actor's name is $lengthOfName.")
    }
    
  • The ?: Elvis operator is an operator that you can use together with the ?. safe-call operator. With the ?: Elvis operator, you can add a default value when the ?. safe-call operator returns null. It’s similar to an if/else expression, but in a more idiomatic way.

  • If the variable isn’t null, the expression before the ?: Elvis operator executes. If the variable is null, the expression after the ?: Elvis operator executes.

    ../_images/unit2-pathway1-activity3-section3-85be2b9161680ecf_1440.png
  • Example:

    fun main() {
        var favoriteActor: String? = "Sandra Solulu"
    
        val lengthOfName = favoriteActor?.length ?: 0
    
        println("The number of characters in your favorite actor's name is $lengthOfName.")
    }
    

Conclusion¶

  • A variable can be set to null to indicate that it holds no value.

  • Non-nullable variables cannot be assigned null.

  • Nullable variables can be assigned null.

  • To access methods or properties of nullable variables, you need to use ?. safe-call operators or !! not-null assertion operators.

  • You can use if/else statements with null checks to access nullable variables in non-nullable contexts.

  • You can convert a nullable variable to a non-nullable type with if/else expressions.

  • You can provide a default value for when a nullable variable is null with the if/else expression or the ?: Elvis operator.