Use nullability in Kotlin

1. 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, and the println() and main() functions
  • Familiarity with Kotlin conditionals, including if/else statements and Boolean expressions
  • Knowledge of Kotlin classes, including how to access methods and properties from a variable.

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

2. Use nullable variables

What is null?

In Unit 1, you learned that when you declare a variable, you need to assign it a value immediately. For example, when you declare a favoriteActor variable, you may assign it a "Sandra Oh" string value immediately.

val favoriteActor = "Sandra Oh"

A box that represents a favoriteActor variable that's assigned a "Sandra Oh" string value.

However, what if you don't have a favorite actor? You might want to assign the variable a "Nobody" or "None" value. This isn't a good approach because your program interprets the favoriteActor variable to have a "Nobody" or "None" value rather than no value at all. In Kotlin, you can use null to indicate that there's no value associated with the variable.

A box that represents afavoriteActor variable that's assigned a null value.

To use null in code, follow these steps:

  1. In Kotlin Playground, replace the content in the body of the main() function with a favoriteActor variable set to null:
fun main() {
    val favoriteActor = null
}
  1. Print the value of the favoriteActor variable with the println() function and then run this program:
fun main() {
    val favoriteActor = null
    println(favoriteActor)
}

The output looks like this code snippet:

null

Variable reassignments with null

Previously, you learned that you can reassign variables defined with the var keyword to different values of the same type. For example, you can reassign a name variable that's declared with one name to another name as long as the new name is of String type.

var favoriteActor: String = "Sandra Oh"
favoriteActor = "Meryl Streep"

There are occasions after you declare a variable when you may want to assign the variable to null. For example, after you declare your favorite actor, you decide that you don't want to reveal your favorite actor at all. In this case, it's useful to assign the favoriteActor variable to null.

Understand non-nullable and nullable variables

To reassign the favoriteActor variable to null, follow these steps:

  1. Change the val keyword to a var keyword, and then specify that the favoriteActor variable is a String type and assign it to the name of your favorite actor:
fun main() {
    var favoriteActor: String = "Sandra Oh"
    println(favoriteActor)
}
  1. Remove the println() function:
fun main() {
    var favoriteActor: String = "Sandra Oh"
}
  1. Reassign the favoriteActor variable to null and then run this program:
fun main() {
    var favoriteActor: String = "Sandra Oh"
    favoriteActor = null
}

You get this error message:

A warning message that says: "Null cannot be a value of a non-null type String".

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 can't 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.

A diagram that shows how to declare nullable type variables. It starts with a var keyword followed by the name of the variable block, a semi colon, the type of the variable, a question mark, the equal sign, and the value block.  The type block and the question mark is denoted with Nullable type text marking that having the type followed with question mark is what makes it a nullable type.

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.

  1. Change the favoriteActor variable type from a String data type to a String? data type:
fun main() {
    var favoriteActor: String? = "Sandra Oh"
    favoriteActor = null
}
  1. Print the favoriteActor variable before and after the null reassignment, and then run this program:
fun main() {
    var favoriteActor: String? = "Sandra Oh"
    println(favoriteActor)

    favoriteActor = null
    println(favoriteActor)
}

The output looks like this code snippet:

Sandra Oh
null

The favoriteActor variable originally held a string and is then converted to null.

Try it

Now that you can use the nullable String? type, can you initialize a variable with an Int value and reassign it to null?

Write a nullable Int value

  1. Remove all the code in the main() function:
fun main() {
    
}
  1. Create a number variable of a nullable Int type and then assign it a 10 value:
fun main() {
    var number: Int? = 10
}
  1. Print the number variable and then run this program:
fun main() {
    var number: Int? = 10
    println(number)
}

The output is as expected:

10
  1. Reassign the number variable to null to confirm that the variable is nullable:
fun main() {
    var number: Int? = 10
    println(number)
    
    number = null
}
  1. Add another println(number) statement as the final line of the program and then run it:
fun main() {
    var number: Int? = 10
    println(number)
    
    number = null
    println(number)
}

The output is as expected:

10
null

3. Handle nullable variables

Previously, you learned to use the . operator to access methods and properties of non-nullable variables. In this section, you learn how to use it to access methods and properties of nullable variables.

To access a property of the non-nullable favoriteActor variable, follow these steps:

  1. Remove all the code in the main() function, and then declare a favoriteActor variable of String type and assign it to the name of your favorite actor:
fun main() {
    var favoriteActor: String = "Sandra Oh"
}
  1. Print the number of characters in the favoriteActor variable value with the length property and then run this program:
fun main() {
    var favoriteActor: String = "Sandra Oh"
    println(favoriteActor.length)
}

The output is as expected:

9

There are nine characters in the value of the favoriteActor variable, which includes spaces. The number of characters in your favorite actor's name might be different.

Access a property of a nullable variable

Imagine that you want to make the favoriteActor variable nullable so that people who don't have a favorite actor can assign the variable to null.

To access a property of the nullable favoriteActor variable, follow these steps:

  • Change the favoriteActor variable type to a nullable type and then run this program:
fun main() {
    var favoriteActor: String? = "Sandra Oh"
    println(favoriteActor.length)
}

You get this error message:

An error message that says, "Only safe or non-null asserted calls are allowed on a nullable receiver of type String?".

This error is a compile error. As mentioned in a previous codelab, 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 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 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. 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 learn about this in the Use if/else conditionals section later in this codelab.

In this example, the code fails at compile time because the direct reference to the length property for the favoriteActor variable isn't allowed because there's a possibility that the variable is null.

Next, you learn various techniques and operators to work with nullable types.

Use the ?. safe-call operator

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

A diagram that shows a nullable variable block followed by a question mark, a dot, and a method or property block. There are no spaces in between.

To use the ?. safe-call operator to access a method or property, add a ? symbol after the variable name and access the method or property with the . notation.

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.

To safely access a property of the nullable favoriteActor variable, follow these steps:

  1. In the println() statement, replace the . operator with the ?. safe-call operator:
fun main() {
    var favoriteActor: String? = "Sandra Oh"
    println(favoriteActor?.length)
}
  1. Run this program and then verify that the output is as expected:
9

The number of characters of your favorite actor's name might differ.

  1. Reassign the favoriteActor variable to null and then run this program:
fun main() {
    var favoriteActor: String? = null
    println(favoriteActor?.length)
}

You see this output:

null

Notice that the program doesn't crash despite an attempt to access the length property of a null variable. The safe-call expression simply returns null.

Use the !! not-null assertion operator

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

A diagram that shows a nullable variable block followed by two exclamation points, a single dot, and a method or property block. There are no spaces in between.

After the nullable variable, you need to add the !! not-null assertion operator followed by the . operator and then the method or property without any spaces.

As the name suggests, 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.

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 in later units of this course.

To access a property of the favoriteActor variable with the !! not-null assertion operator, follow these steps:

  1. Reassign the favoriteActor variable to your favorite actor's name and then replace the ?. safe-call operator with the !! not-null assertion operator in println() statement:
fun main() {
    var favoriteActor: String? = "Sandra Oh"
    println(favoriteActor!!.length)
}
  1. Run this program and then verify that the output is as expected:
9

The number of characters of your favorite actor's name might differ.

  1. Reassign the favoriteActor variable to null and then run this program:
fun main() {
    var favoriteActor: String? = null
    println(favoriteActor!!.length)
}

You get a NullPointerException error:

An error message that says, "Exception in thread "main" java.lang.NullPointerException".

This Kotlin error shows that your program crashed during execution. As such, it's not recommended to use the !! not-null assertion operator unless you're sure that the variable isn't null.

Use the if/else conditionals

You can use the if branch in the if/else conditionals to perform null checks.

A diagram that shows a nullable variable block followed by an exclamation point, an equal sign, and null.

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

if/else statements

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

A diagram that describes an if/else statement with the if keyword followed by parentheses with a null check block inside them, a pair of curly braces with body 1 inside them, an else keyword, and another pair of curly braces with a body 2 block inside them. The else clause is encapsulated with a dotted red box, which is annotated as optional.

The null check is useful when combined with an if/else statement:

  • The null check of the nullableVariable != null expression is used as the if condition.
  • Body 1 inside the if branch assumes that the variable is non-nullable. Therefore, in this body, you can freely access methods or properties of the variable as if it's a non-nullable variable without using a ?. safe-call operator or a !! not-null assertion operator.
  • Body 2 inside the else branch assumes that the variable is null. Therefore, in this body, you can add statements that should run when the variable is null. The else branch is optional. You can use only the if conditional to run a null check without providing default action when the null check fails.

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.

To write an if/else statement with a null check for the favoriteActor variable, follow these steps:

  1. Assign the favoriteActor variable to the name of your favorite actor again and then remove the println() statement:
fun main() {
    var favoriteActor: String? = "Sandra Oh"

}
  1. Add an if branch with a favoriteActor != null condition:
fun main() {
    var favoriteActor: String? = "Sandra Oh"

    if (favoriteActor != null) {

    }
}
  1. In the body of the if branch, add a println statement that accepts a "The number of characters in your favorite actor's name is ${favoriteActor.length}" string and then run this program:
fun main() {
    var favoriteActor: String? = "Sandra Oh"

    if (favoriteActor != null) {
      println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
    }
}

The output is as expected.

The number of characters in your favorite actor's name is 9.

The number of characters in your favorite actor's name might differ.

Notice that you can access the name's length method directly with the . operator because you access the length method inside the if branch after the null check. As such, the Kotlin compiler knows that there's no possibility that the favoriteActor variable is null, so the compiler allows direct access to the property.

  1. Optional: Add an else branch to handle a situation in which the actor's name is null:
fun main() {
    var favoriteActor: String? = "Sandra Oh"

    if (favoriteActor != null) {
      println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
    } else {

    }
}
  1. In the body of the else branch, add a println statement that takes a "You didn't input a name." string:
fun main() {
    var favoriteActor: String? = "Sandra Oh"

    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.")
    }
}
  1. Assign the favoriteActor variable to null and then run this program:
fun main() {
    var favoriteActor: String? = null

    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.")
    }
}

The output is as expected:

You didn't input a name.

if/else expressions

You can also combine the null check with an if/else expression to convert a nullable variable to a non-nullable variable.

A diagram that describes an if/else expression with the val keyword followed by a name block, a colon, and non-null type block, an equal symbol, the if keyword, parentheses with a condition inside them, a pair of curly braces with body 1 inside them, an else keyword with another pair of curly braces, and a body 2 block inside them.

To assign an if/else expression to a non-nullable type:

  • The nullableVariable != null null check is used as the if condition.
  • Body 1 inside the if branch assumes that the variable is non-nullable. Therefore, in this body, you can access methods or properties of the variable as if it's a non-nullable variable without a ?. safe operator or a !! not-null assertion operator.
  • Body 2 inside the else branch assumes that the variable is null. Therefore, in this body you can add statements that should run when the variable is null.
  • In the final line of body 1 and 2, you need to use an expression or value that results in a non-nullable type so that it's assigned to the non-nullable variable when the null check passes or fails respectively.

To use the if/else expression to rewrite the program so that it only uses one println statement, follow these steps:

  1. Assign the favoriteActor variable to the name of your favorite actor:
fun main() {
    var favoriteActor: String? = "Sandra Oh"

    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.")
    }
}
  1. Create a lengthOfName variable and then assign it to the if/else expression:
fun main() {
    var favoriteActor: String? = "Sandra Oh"

    val lengthOfName = 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.")
    }
}
  1. Remove both println() statements from the if and else branches:
fun main() {
    var favoriteActor: String? = "Sandra Oh"

    val lengthOfName = if(favoriteActor != null) {
      
    } else {
      
    }
}
  1. In the body of the if branch, add a favoriteActor.length expression:
fun main() {
    val favoriteActor: String? = "Sandra Oh"

    val lengthOfName = if(favoriteActor != null) {
      favoriteActor.length
    } else {
      
    }
}

The length property of the favoriteActor variable is accessed directly with the . operator.

  1. In the body of the else branch, add a 0 value:
fun main() {
    val favoriteActor: String? = "Sandra Oh"

    val lengthOfName = if(favoriteActor != null) {
      favoriteActor.length
    } else {
      0
    }
}

The 0 value serves as the default value when the name is null.

  1. At the end of the main() function, add a println statement that takes a "The number of characters in your favorite actor's name is $lengthOfName." string and then run this program:
fun main() {
    val favoriteActor: String? = "Sandra Oh"

    val lengthOfName = if(favoriteActor != null) {
      favoriteActor.length
    } else {
      0
    }

    println("The number of characters in your favorite actor's name is $lengthOfName.")
}

The output is as expected:

The number of characters in your favorite actor's name is 9.

The number of characters of the name that you used might differ.

Use the ?: Elvis operator

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.

A diagram that shows the val keyword followed by a name block, an equal sign, a nullable variable block, a question mark, a dot, a method or property block, a question mark, a colon, and a default value block.

To modify your previous program to use the ?: Elvis operator, follow these steps:

  1. Remove the if/else conditional and then set the lengthOfName variable to the nullable favoriteActor variable and use the ?. safe-call operator to call its length property:
fun main() {
    val favoriteActor: String? = "Sandra Oh"

    val lengthOfName = favoriteActor?.length

    println("The number of characters in your favorite actor's name is $lengthOfName.")
}
  1. After the length property, add the ?: Elvis operator followed by a 0 value and then run this program:
fun main() {
    val favoriteActor: String? = "Sandra Oh"

    val lengthOfName = favoriteActor?.length ?: 0

    println("The number of characters in your favorite actor's name is $lengthOfName.")
}

The output is the same as the previous output:

The number of characters in your favorite actor's name is 9.

4. Conclusion

Congratulations! You learned about nullability and how to use various operators to manage it.

Summary

  • 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.

Learn more