Kotlin Null Safety

As a developer, we always have faced NullPointerException, or commonly known as ‘The Billion Dollar Mistake’. Every introduction of kotlin talks about the kotlin’s capablity to handle Null Pointers. Yes, take it as a relief Kotlin can handle null pointers for you, thanks to its type system.

The type system of kotlin is designed keeping in mind to handle the ‘Null pointer Exception’. One of major issues which developers run into or ramp into is the Null Pointer Exception for many programming languages including Java.  It occurs due to the accessing of members which have a null reference. A typical way of handling null pointer in Java is shown below:

String str= null;
if (str != null) {
    System.out.println(str.length)
} else {
    System.out.println("String str is null.")
}

Since this type system is not available in Java, developer needs to handle the case for every null value explicitly.

Causes for Arising of Null Pointer Exception

NPE can arise due one of the reasons or issues arising in our code.

  1. Throw Keyword: When the developer explicitly calls ‘throw NullPointerException()’
  1. Data Inconsistency: This could occur due to one of the reasons:
    • if this keyword is uninitialized and available to a constructor is passed and used somewhere
    • A constructor of the superclass calls an open member
  1. Java interoperation: When a member function is accessed on a reference which is null.
  2. Code Issues caused by External Java Code.

To solve the issue above, kotlin has a separate type system for it. Let’s have look at Kotlin type systems in detail.

Kotlin Null Safety

Kotlin Null safety
Image Source

Kotlin language has two distinct types of type system that can be used to hold references for either type i.e. Nullable Type System (holding Nullable references) and Non – Nullable Type System (holding non Nullable references). Let’s understand their working in detail as below:

Kotlin Non Nullable Type Reference

The default type of reference which assumes or forces that variable or reference cannot be null. Let’s take an example of variable of type String ‘str’, if we try to assign it value as null. It would give an error as below:

var str: String = "hello"
str = null // compilation error

The above part of the code gives compilation error as Kotlin does not allows Non Nullable reference types to be null. Now, let’s have look at Nullable type system:

Kotlin Nullable Type Reference

To make a reference as null, kotlin has separate reference type for each of the type known as Nullable type. For example, Nullable string can be declared by using Nullable string, written as String?

var str2: String? = "Kotlin Tutorial Blog"
str2 = null // this would not result in compilation error
print(str2)

Since non Nullable reference variables can never be null. We can simply call the length member function or attribute and be rest assured that NPE wouldn’t occur.

val strLen = str.length
fun main(args: Array<String>){ 
	// variable is declared as non-nullable 
	var str : String = "hello"

	//str = null // Compilation error
	
	print("The length of string str is: "+str.length) 
}

Output:

The length of string str is: 5

In the example above, we saw that assigning null to a variable results in compile time error. Also note that since the type is non nullable we can be rest assured that accessing the length won’t throw NullPointerException.

Now, if you wish to access the length of string str2, it would not be safe and the compiler reports an error as below (since compiler understands that this variable could be null):

val str2Len = s2.length         // This would give an error as str2 can be null
fun main(args: Array<String>) { 
	// variable is declared as nullable 
	var str2: String? = "Kotlin Tutorial Blog"
	str2 = null // This would not result in compilation error 
	println(str2.length) // This part of code will result in compile time error. 
}

The above code will not compile as the variable may be null, we will get the following compilation error:

Error:(8, 15) Kotlin: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?

In case of nullable reference type of variables we can assign variables as null but since the output of these variables may return NullPointerException, we need to use the safe operator in order to access the length of the string

Checking for Null Condition Using if-else

fun main(args: Array<String>) { 
	// Nullable Type Reference Variable
	var str: String? = "Kotlin Tutorial Blog"
	println(str) 
	if (str != null) { 
		println("String of length ${str.length}") 
	} else { 
		println("Null string") 
	} 
	// assign null 
	str = null
	println(str) 
	if (str != null) { 
		println("String of length ${str.length}") 
	} else { 
		println("Null String") 
	} 
}

Output:

Kotlin Tutorial Blog
String of length 20
null
Null String

Using the above if-else blocks would make code repetitive and difficult to understand. Making languages simple, Kotlin came up with a concept of Safe Operator (?.) as explained in the example below.

The Safe Call Operator (?.)

Comparisons with Null though simple as seen above but such huge number of if-else expression before each use of variable will add to a lot of boiler plate code. So, here comes the Safe call operator. As it may sound, by a simple use of (?.) we can reduce the complexity of our code and the action is executed only when the reference/variable has a non-null value. In simple words, it is merging the null check and method call in a single expression.

Example: For the code to check null:

if (str != null) { 
		println("String of length ${str.length}") 
	} else { 
		println("Null String") 
	}

The entire code can be reduced to a single expression as str?.length

Let see a use case of Safe Operator in Kotlin:

fun main(args: Array<String>) { 
	 
	var fName: String? = "ABC" // Nullable Type Reference variable
	var lName: String? = null

	println(fName?.toUpperCase()) 
	println(fName?.length) 
	println(lName?.toUpperCase())
	
}

Output:

ABC
7
null

The above operator can be used with any data type like equivalent of Int becomes Int?.

Chaining of Safe Operator

We can use safe expressions while chaining of references as below.

For example, if Stu, a Student, is assigned to a Section (or not), that in turn may have another SectionMentor as a class mentor, then to obtain the name of stu’s class mentor (if any), we would write the following code:

stu?.section?.mentor?.name

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

Having gone through the safe operators and their usage, there may be cases where we would want expression to be called only if the value encountered is not null we can use the let operator.

val someList: List<String?> = listOf("KotlinTut", null)
for (str in someList) {
    str?.let { println(it) } // prints KotlinTut and ignores null
}

In the example above, KotlinTut is printed and null is ignored. The lambda expression of let is executed only when the value is not null i.e. when the value is KotlinTut.

fun main(args: Array<String>) { 
	// List with string and null values 
	var strList: List<String?> = listOf("Kotlin","Tutorial", null) 
	
	var finList = listOf<String?>()  // A new blank list
	for (item in strList) { 
		item?.let { finList = finList.plus(it) } // Lambda expression is executed only if value is not null
	} 
	for(str in finList){ 
		println(str) // Printing all values in the new list
	} 
}

Output:

Kotlin
Tutorial

Kotlin’s also() Method

Along with the application of let() method if you want to apply certain other operation on non-nullable items we can use the also() method. The working of also method is similar to let(), it’s a lambda expression which provides a

If we want to apply some additional operation like printing the non-nullable items of the list we can use an also() method and chain it with a let() or run().

Let’s continue the same example and add the also() method:

fun main(args: Array<String>) { 
	// List with string and null values 
	var strList: List<String?> = listOf("Kotlin","Tutorial", null) 
	
	var finList = listOf<String?>()  // A new blank list
	for (item in strList) { 
		item?.let {finList = finList.plus(it) } //Lambda expression is executed only if value is not null
		item?.also{it -> println(it)} // Use of also on not null values
	}
}

Output:

Kotlin
Tutorial

Having gone the let() and also() methods, let’s have a look at run() method. This method can be used when we want to operate on nullable references.

Kotlin’s run() Method

Kotlin provides a run() method, which can be used to execute operations on nullable references. The run() is quite similar to the let() method just for the fact, inside the body/lambda expression we can use the this reference, rather than any function parameter.

fun main(args: Array<String>) { 
	// List with string and null values 
	var strList: List<String?> = listOf("Kotlin","Tutorial", null) 
	
	var finList = listOf<String?>()  // A new blank list
	for (item in strList) { 
		item?.run  {finList = finList.plus(this) } //Lambda expression is executed only if value is not null
		item?.also{it -> println(it)} // Use of also on not null values
	}
}

Take a note that also, can be used with both let and run method.

What should happen when we want to operate on null values in or if we want an operation to be like if null perform an operation else perform the other operation. To take care of this issue we have an operator known as Elvis Operator.

Elvis Operator

When we have a nullable reference ‘refer’, we can simply use a non null value or some other value ‘x’. Let’s have a look as below:

Using If (Conditional Flow):

val x: Int = if (x != null) x.length else -1

In the example above, we are using if condition to check if the value of a nullable reference is null. The same expression can be shortened using the Elvis operator, expressed by ?::

val x = x?.length ?: -1

Syntax:

variable?.<if not null> ?: else if null

Lets try to above concept with the help of an example:

fun main(args: Array<String>) { 
	var s : String? = "Kotlin" // Nullable Refernce 
	println(s?.length) 
	s = null // Setting Nullable reference to null
	println(s?.length ?: "-1") 
} 

Output:

6
-1

Not Null Operator

Kotlin provides us with another operator and converts any value to a non-null type and if the value found is null it throws an exception.

Lets modify the above example and understand about not null operator:

fun main(args: Array<String>) { 
	var s : String? = "Kotlin" // Nullable Refernce 
	println(s!!.length) 
	s = null // Setting Nullable reference to null
	s!!.length 
}

Output:

6
Exception in thread “main” kotlin.KotlinNullPointerException……..(entire stack trace)

The above code works perfectly fine when the value is “Kotlin”, but throws an Exception when the value is null.

That was all about the operators provided by kotlin to handle null safety, now let’s how we can use Collections of the Nullable type:

Out of collection of nullable reference if you wish to filter all non null elements, the same can be done using ‘filterNotNull’:

val dummyList: List<Int?> = listOf(1, 2, null,34)
val newDummyList: List<Int> = dummyList.filterNotNull()

That was about the all possible use cases of Null able types and how Kotlin makes the use of type system, to ensure that your code doesnot throws up “NullPointerException”.

That was all about NPE and kotlin null safety. Comment down below if you have any queries.

Leave a Comment

Your email address will not be published. Required fields are marked *