Tuesday, May 22, 2018

Kotlin - Null Safety

If you have used Java for web or mobile application development. You might have definitely face  NPE (NullPointerException).


NPE is runtime exceptions which are thrown by the program at runtime causing application failure and system crashes. It is not a good thing if your app crashes and face NPE exception errors.

Null Safety in Kotlin is eliminating the risk of occurrence of NPE in real time.  Kotlin can detect NPE exception errors at compile time itself and guard against them.

Kotlin could never throw a NullPointerException unless you ask for it.

Kotlin has two types of references that are interpreted by the compiler that gives information to the programmer about the correctness of a program at compile time.

1. Nullable Reference.
2. Non-Nullable Reference.

Kotlin supports nullability as part of its type System. It means you have the ability to declare whether a variable can hold a null value or not. By supporting nullability in the type system, the compiler can detect possible NullPointerException errors at compile time and reduce the possibility of having them thrown at runtime.


Let’s understand how it works!

All variables in Kotlin are non-nullable by default. So If you try to assign a null value to a regular variable, the compiler will throw an error.
Example-1
var name: String = "Kotlin"
name= null // Compilation Error
To allow null values, you have to declare a variable as nullable by appending a question mark (?) in its type declaration.
Example-2
var name: String? = "Kotlin"
name= null // it will work.
As we know that NullPointerException occurs in Java when we try to call a method or access a property on a variable which is null.  Kotlin disallows method calls and property access on nullable variables and thereby prevents many possible NullPointerExceptions at compile time.

The following method access works because Kotlin knows that the variable greeting can never be null.
Example-3
var name: String = "Kotlin"
//But the same method call won’t work with name variable
val upper = name.toUpperCase() 
But the same method call won’t work with name variable.
Example-4
var name: String? = "Kotlin"
// Compilation Error
val upper = name.toUpperCase() 
As you see, Kotlin knows which variable can be null and which cannot, It can detect and disallow calls which could result in NullPointerException at compile-time itself.

But, there are some ways of safely access object properties in Kotlin. We can check null objects before execute.
Example-5
val nullableName: String? = "Kotlin"
if(nullableName != null) {
    println("Hello, ${nullableName.toUpperCase()}.")
    println("I'm working on ${nullableName.length} characters long.")
} else {
    println("Hello, Kotlin")
} 

Safe Call

Kotlin has a safe call operator (?.) that returns the variable's property only if the variable is not null, otherwise, it returns null. So the variable holding the return value should be declared nullable. Following is the example program where a safe call is made with the variable name.

Example-6
var name: String? = "Kotlin"
name?.toUpperCase()
//It is same as Java.
String name="kotlin";
if(name!= null) 
    name.toUpperCase()
els
    null
//You can observe here, That saves a lot of keystrokes.


Elvis Operator (?:)


It is the same as safe calls except, it can return a non-null value if the calling property is null even.
The Elvis operator will evaluate the left expression and will return it if it’s not null else will evaluate the right side expression. This might sound same as explicitly checking for a null value. But the syntax could be reduced and is given below :
Example-7
var name : String?  = "kotlin"
println(name?.length) //prints 6
name = null
println(name?.length?:"-1") //prints -1
//The elvis operator is equivalent explicitly check.
if(name!null)
{
  print(name.length)
}
else{
   print("-1")
}
//elvis chain:
var streetName : String? = address?.locality?.street?.addressLine1 ?: "Street Name not found"
The exclamation mark (!!) Operator.

You can use it if you need NPE.  It can convert a nullable type to a non-null type and throws a NullPointerException if the nullable type holds a null value.
Example-8
val name: String? = null
name!!.toUpperCase() //It’s a way of asking for NPE.
This should be used only when you’re certain that the value is NOT NULL. Else it’ll lead to an NPE exception.

The let() method.

Let function executes the lambda function specified only when the reference is non-nullable as shown below.

Example-9
name = " Kotlin from Android"
anem?.let { println("The string value is: $it") }
name = null
name?.let { println("The string value is: $it") }
The statement inside let is a lambda expression. It’s only run when the value of the name is not null.
it contains the non-null value of name.

The also() method.

It behaves the same way as for let() except that it’s generally used to log the values or you can apply some additional operation. We can use an also() method and chain it with a let().

Example-10
var res = listOf<String?>()
for (item in names) {
    item?.let { res = res.plus(it); it }
  ?.also{it -> println("non nullable value: $it")}
}





The run() method.


Kotlin has a run() method to execute some operation on a nullable reference. It is very similar to let() but inside of a function body, the run() method operates on this reference instead of a function parameter:

Example-11
var res = listOf<String?>()
for (item in names) {
    item?.run{res = res.plus(this)}
}

Null Safety and Java Interoperability.

Kotlin is fully interoperable with Java but Java doesn’t support nullability in its type system.


So what happens. When you call Java code from Kotlin?

Java types are treated specially in Kotlin. It doesn’t have any information about the nullability of a type declared in Java, It relaxes compile-time null checks for these types.

So you don’t get any null safety guarantee for types declared in Java, and you have full responsibility for operations you perform on these types. The compiler will allow all operations. If you know that the Java variable can be null, you should compare it with null before use, otherwise, just like Java, you’ll get a NullPointerException at runtime if the value is null.

Consider the following User class declared in Java -

Java class
public class User {
    private final String name;
    public User(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
Kotlin allows all java operations on this variable. You can treat it as nullable or non-nullable, but the compiler won’t enforce anything.

We simply treat the variable name as non-nullable and call methods and properties on it.
Example-12
val javaUser = User(null)
println(javaUser.name.toUpperCase()) // Allowed (Throws NPE if found null)
The other option is to treat the member variable name as nullable and use the safe operator for calling methods or accessing properties.
Example-13
val javaUser = User(null)
println(javaUser.name?.toUpperCase()) // Allowed (Prints null)

Nullability and Collections.

Kotlin collection API is built on top of Java’s collection API but it fully supports nullability on Collections. Just as regular variables are non-null by default, a normal collection also can’t hold null values.

Example-14
val regularList: List<Int> = listOf(1, 2, null, 3) // Compiler Error
But, we can declare a Collection of Nullable Types in Kotlin.
Example-15
val listOfNullableTypes: List<Int?> = listOf(1, 2, null, 3) // Works
To filter non-null values from a list of nullable types, you can use the filterNotNull() function.
Example-16
val list: List<String?> = listOf("a", null, "b")
val res = list.filterNotNull()
assertEquals(res.size, 2) 
assertTrue { res.contains("a") } 
assertTrue { res.contains("b") }

Nullable Collection.

Note that there is a difference between a collection of nullable types and a nullable collection. A collection of nullable types can hold null values but the collection itself cannot be null.
Example-17
var listOfNullableTypes: List<Int?> = listOf(1, 2, null, 3) // Works
listOfNullableTypes = null // Compilation Error
You can declare a nullable collection like this.
Example-18
var nullableList: List<Int>? = listOf(1, 2, 3)
nullableList = null // Works


So, we have learned what Null Safety is, differences between nullable references and non-nullable references and its operator. But if you still have any doubt, please feel free to clarify that in the comment section below.


Previous                                                                                   Next


Share:

Get it on Google Play

React Native - Start Development with Typescript

React Native is a popular framework for building mobile apps for both Android and iOS. It allows developers to write JavaScript code that ca...