Introduction
The type system in Kotlin aims to reduce the risk of null references from the code because it is a costly error. The software can throw NullPointerExceptions at runtime, which can occasionally result in application failure or system failures.
Anyone who has ever written Java or another programming language with the idea of a null reference must have seen a NullPointerException. Additionally, the Kotlin compiler will throw a NullPointerException if it encounters a null reference while no additional statements are being executed.
The following are some potential causes of NullPointerException:
- Explicit call to throw NullPointerException()
- Use of the !! operator
- Some data inconsistency with regard to initialization e.g. an uninitialized this is passed as an argument.
- Java interoperations such as attempts to access a member on a null reference, generics type with incorrect nullability.
Nullable and Non-Nullable Types in Kotlin
Kotlin type system has distinguished two types of references that can hold null (nullable references) and those that can not (non-null references).
A variable of type String can not hold null. If we try to assign null to the variable, it gives a compiler error.
Example :
var s1: String = “Hello”
s1 = null // compilation error
To allow a variable to hold null, we can declare a variable as nullable string, written String?
var s2: String? = “Good Morning”
s2 = null // ok
Now, if we want to access the length of the string s1, it guarantees not to throw NPE, so we can safely say:
val l = s1.length
But if we want to access the length of the string s2, that would not be safe, and the compiler reports an error:
val l = s2.length // error: variable ‘s2’ can be null
Output : Error:(8, 15) Kotlin: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
Here, we can easily assign null to a nullable type variable. But we should use the safe operator to get the length of the string.
Safe Call operator(?.)
Null Comparisons are simple, but the number of nested if-else expressions could be burdensome. So, Kotlin has a Safe call operator, ?. That reduces this complexity and executes an action only when the specific reference holds a non-null value.. It allows us to combine a null-check and a method call in a single expression.
Example:
firstName?.toUpperCase()
is equivalent to:
if(firstName != null)
firstName.toUpperCase()
Else
Null
Elvis Operator(?:)
When the initial variable is null, the Elvis operator is used to return a non-null value or a default value. In other words, the Elvis operator returns the right expression if the left expression is null and the left expression is not. Only if the left side is discovered to be null is the right side expression evaluated.
The following expression:
val name = firstName ?: “Unknown”
is equivalent to:
val name = if(firstName!= null)
firstName
else
“Unknown”
Additionally, the throw and return expressions may be used on the right side of the Elvis operator, which is quite helpful in functions. Therefore, on the right side of the Elvis operator, we may throw an exception instead of returning a default value.
Not null assertion : !! Operator
The not null assertion (!!) operator converts any value to a non-null type and throws an exception if the value is null.
If anyone wants a NullPointerException then he can ask explicitly using this operator.
Conclusion
Kotlin gives you a lot of flexibility of action and has a variety of operators and built-in utilities to deal with null safety. Null safety is one of the most crucial characteristics included with Kotlin since it has supported these operators from the start.