Working with null values

Many programming languages support null values. Null values are treated as valueless and are typically used to indicate the absence of data. While null values are commonplace throughout many applications, interactions with null data can cause exceptions such as NullPointerException to be thrown if the application code is not equipped to handle null values.

Null-safe calls

Some programming languages such as Kotlin feature the ability to make null-safe calls to an object's methods and properties. Null-safe calls return null when you attempt to interact with a null object, where otherwise a NullPointerException may be thrown. For example, in the below Kotlin code, there is a list variable called names which are set to null. As it stands, when we attempt to call the list's isNotEmpty method, a NullPointerException will be thrown because we are attempting to interact with a null object in a non-null-safe manner.

fun main(args: Array<String>) {
	val names: List<String>? = null
	
	// Non null-safe call. Will throw a NullPointerException
	val isNotEmpty: Boolean = names!!.isNotEmpty()
}

To avoid the NullPointerException, we must accommodate for the names list potentially being null. This can be achieved using a null-safe call. To construct a null-safe call in Kotlin, simply input a question mark (?) after the object or value that is potentially null. When the code runs, if the object or value is non-null, then the code will run as normal; however, if the object or value is null, then a value of null will be returned instead and the line of code will not be processed any further. No NullPointerException will be thrown.

fun main(args: Array<String>) {
	val names: List<String>? = null
	
	// Null-safe call. isNotEmpty will equal null
	var isNotEmpty: Boolean? = names?.isNotEmpty()
    // Prints null
    println(isNotEmpty)
    
    names = listOf("James", "Anna")
    
    // Null-safe call. isNotEmpty will equal true
	isNotEmpty = names?.isNotEmpty()
    // Prints true
    println(isNotEmpty)
}

Conditional null checks

Many coding languages support conditional null checks, which use if/else expressions to determine the appropriate course of action if a value is null. For example, the below JavaScript code will print "You are signed in." to the console only if the variable username is not null. Otherwise, the else block will print "You are signed out." to the console instead.

let username = "codersgu";

if (username === null) {
    console.log("You are signed out.")
} else {
    console.log("You are signed in.")
}

In some languages such as Kotlin, it is possible to directly use condition null checks in the assignment of a variable's value. For example, the below Kotlin code defines a function called setUsername that accepts an argument called username. The value of the username may be null. If the username variable is null, then the conditional null check will set the value of the parent class's username variable to "Unknown user". Otherwise, the supplied username will be used as normal.

class UserDetails {
	private var username = ""
				
	fun setUsername(username: String?) {
		this.username = if (username != null) username
		else "Unknown user"
	}
}

Elvis operator

Coding languages such as Kotlin, PHP, JavaScript, C++ and others support handling null various using variations of a feature called the Elvis operator. The Elvis operator provides a backup value that can be used if the first-choice value is null. The Elvis operator got its name because in languages such as Kotlin the operator is written as ?:, which when rotated clockwise looks like Elvis Presley and his quiff. To use the Elvis operator, input your first-choice value on the left-hand side of the operator, and your backup value on the right-hand side of the operator. The backup value will be used only if the first-choice value is null.

For example, the below Kotlin code iterates through a list of Strings and prints each value to the console. Some of the elements in the list are set to null. If the iterator encounters a null element, then the Elvis operator causes "Missing String" to be printed to the console instead.

fun main(args: Array<String>) {
	val listOfStrings = listOf("Apple", null, "Carrot", null)
	
	/*
	 * Prints:
	 *  Apple
     *  Missing String
     *  Carrot
     *  Missing String
	*/
	for (element in listOfStrings) {
		println(element ?: "Missing String")
	}
}