Contents
Kotlin and Null Safety
Kotlin’s type system is designed to eliminate the risk of null reference errors from the code. NullPointerExceptions (NPE) often cause unexpected runtime crashes and application failures. Kotlin aims to prevent this billion-dollar mistake by handling null references at compile-time.
If you’re coming from Java or another language with null references, you’ve likely experienced NullPointerExceptions. Kotlin’s compiler throws a NullPointerException if it detects an unhandled null reference without proceeding with further execution.
Common causes of NullPointerException:
- Explicitly calling
throw NullPointerException()
- Using the
!!
operator - Uninitialized data, such as passing an uninitialized
this
reference as an argument - Java interoperability issues, such as trying to access a member on a null reference, or using generics with incorrect nullability
Nullable and Non-Nullable Types in Kotlin
In Kotlin, references are either nullable or non-nullable. Non-nullable references cannot hold null
values. If you attempt to assign null
to a non-nullable reference, the compiler will raise an error.
var s1: String = "Hello"
s1 = null // Error: compilation issue
However, to declare a variable that can hold null
, we use a nullable type by appending ?
to the type:
var s2: String? = "Hello Kotlin"
s2 = null // No compilation error
If you want to access the length of a nullable string, you must use safe calls or handle the possibility of a null value:
val length = s2?.length // Safe call, returns null if s2 is null
Example: Non-Nullable Type in Kotlin
fun main() {
var s1: String = "Kotlin"
println("The length of the string s1 is: ${s1.length}")
}
Output:
The length of the string s1 is: 6
In this case, assigning null
to s1
would result in a compilation error.
Example: Nullable Type in Kotlin
null
Output:
var s2: String? = "Hello Kotlin"
s2 = null // No compilation error
Here, Kotlin allows assigning null
to s2
since it is a nullable type, but accessing its properties requires safe calls.
Checking for null
in Conditions
You can use if-else
blocks to check if a variable is null
:
fun main() {
var s: String? = "Kotlin"
if (s != null) {
println("String length is ${s.length}")
} else {
println("Null string")
}
s = null
if (s != null) {
println("String length is ${s.length}")
} else {
println("Null string")
}
}
Output:
String length is 6
Null string
Safe Call Operator ?.
The ?.
operator simplifies null checks. If the value before the ?.
is null
, the expression after ?.
is not evaluated, and null
is returned.
fun main() {
var firstName: String? = "Alice"
var lastName: String? = null
println(firstName?.toUpperCase()) // Output: ALICE
println(lastName?.toUpperCase()) // Output: null
}
let()
Function with Safe Call
The let()
function executes only when the reference is not null
:
fun main() {
var firstName: String? = "Alice"
firstName?.let { println(it.toUpperCase()) } // Output: ALICE
}
Example using let()
with Nullable Values
fun main() {
val stringList: List = listOf("Hello", "World", null, "Kotlin")
val filteredList = stringList.filterNotNull()
filteredList.forEach { println(it) }
}
Output:
Hello
World
Kotlin
The Elvis Operator ?:
The Elvis operator returns a default value when the expression on the left is null
:
fun main() {
var str: String? = null
val length = str?.length ?: -1
println(length) // Output: -1
}
Example using the Elvis Operator
fun main() {
var str: String? = "Kotlin"
println(str?.length ?: "-1") // Output: 6
str = null
println(str?.length ?: "-1") // Output: -1
}
Not Null Assertion Operator !!
The !!
operator forces Kotlin to treat a nullable type as non-null. It will throw a KotlinNullPointerException
if the value is null
.
fun main() {
var str: String? = "Kotlin"
println(str!!.length)
str = null
println(str!!.length) // Throws KotlinNullPointerException
}
Output:
6
Exception in thread "main" kotlin.KotlinNullPointerException
Explicit Type Casting
In Kotlin, smart casting allows us to use the is
or !is
operator to check the type of a variable. Once the type is confirmed, the compiler automatically casts the variable to the desired type. However, in explicit type casting, we use the as
operator.
Explicit type casting can be performed in two ways:
- Unsafe cast operator:
as
- Safe cast operator:
as?
- Unsafe Cast Operator:
as :
When using theas
operator, we manually cast a variable to the target type. However, if the casting fails, it results in a runtime exception. This is why it’s considered unsafe. Example
fun main() {
val text: String = "This works!"
val result: String = text as String // Successful cast
println(result)
}
Output:
This works!
While this example works fine, using the as
operator to cast an incompatible type will throw a ClassCastException
at runtime.
For instance, attempting to cast an Integer
to a String
:
fun main() {
val number: Any = 42
val result: String = number as String // Throws exception
println(result)
}
Output:
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String
Similarly, trying to cast a nullable type to a non-nullable type will result in a TypeCastException
:
fun main() {
val text: String? = null
val result: String = text as String // Throws exception
println(result)
}
Output:
This works!
Similarly, trying to cast a nullable type to a non-nullable type will result in a TypeCastException
:
fun main() {
val text: String? = null
val result: String = text as String // Throws exception
println(result)
}
Output:
Exception in thread "main" kotlin.TypeCastException: null cannot be cast to non-null type kotlin.String
To prevent this, we should cast to a nullable target type:
fun main() {
val text: String? = null
val result: String? = text as String? // Successful cast
println(result)
}
Output:
null
Safe Cast Operator: as?:
Kotlin provides a safer option with the as?
operator, which returns null
if the casting fails, instead of throwing an exception.
Here’s an example of using as?
for safe typecasting:
Safe Cast Operator: as?
Kotlin provides a safer option with the as? operator, which returns null if the casting fails, instead of throwing an exception.
Here’s an example of using as? for safe typecasting:
Output:
Safe casting
null
99