Kotlin Null Safety

Null means "no value" — nothing is there. In many programming languages, accidentally using a null value crashes the program with a NullPointerException. Kotlin prevents this at the language level by separating types that can hold null from types that cannot.

The Problem with Null

// In Java, this compiles but crashes at runtime:
String name = null;
int length = name.length();  // NullPointerException — app crashes!

// Kotlin stops this at compile time:
val name: String = null     // ERROR: Null can not be a value of type String

Kotlin's type system forces you to handle null explicitly. You decide which variables can be null, and Kotlin makes sure you never forget to check.

Nullable Types — Adding a Question Mark

Add a ? after a type to allow null. A type without ? can never be null.

val a: String = "Hello"    // Cannot be null
val b: String? = null      // Can be null
val c: String? = "World"   // Also valid for nullable type

var score: Int = 10        // Cannot be null
var topScore: Int? = null  // Can be null

Diagram — Nullable vs Non-Nullable

Type String (non-nullable)       Type String? (nullable)
┌────────────────────┐           ┌────────────────────┐
│ Only holds text    │           │ Holds text OR null │
│ "Hello", "Kotlin"  │           │ "Hello", null      │
│ "" (empty string)  │           │ "" (empty string)  │
│ null → COMPILE     │           │ null → OK          │
│        ERROR       │           │                    │
└────────────────────┘           └────────────────────┘

Safe Call Operator — ?.

The safe call operator (?.) calls a method or accesses a property only if the value is not null. If the value is null, it returns null instead of crashing.

val name: String? = "Kotlin"
println(name?.length)    // 6

val empty: String? = null
println(empty?.length)   // null (no crash)

// Chaining safe calls
data class Address(val city: String?)
data class User(val name: String, val address: Address?)

val user: User? = User("Dev", Address(null))
println(user?.address?.city)   // null — safe at every step

Elvis Operator — ?: Providing a Default

The Elvis operator (?:) provides a fallback value when the left side is null.

val input: String? = null

val displayName = input ?: "Anonymous"
println(displayName)   // Anonymous

val length = input?.length ?: 0
println(length)   // 0

// Chain with logic
val serverName: String? = null
val connectedTo = serverName ?: throw IllegalStateException("No server!")

Non-Null Assertion — !! (Use with Caution)

The !! operator tells Kotlin: "I am certain this is not null. Trust me." If you are wrong and the value is null, Kotlin throws a NullPointerException. Only use this when you are 100% sure the value exists.

val city: String? = "Bengaluru"
println(city!!.length)   // 9 — works fine

val nothing: String? = null
println(nothing!!.length)  // KotlinNullPointerException — CRASH!

The !! is an escape hatch, not a solution. Avoid it unless you have no alternative.

Safe Cast — as?

The as? operator attempts to cast a value to a type. If the cast fails, it returns null instead of throwing an exception.

val obj: Any = "Hello"
val str: String? = obj as? String    // "Hello"
val num: Int? = obj as? Int          // null (not an Int, no crash)

println(str)   // Hello
println(num)   // null

let — Executing Code Only When Not Null

Combine ?. with let to run a block of code only when a nullable value is not null.

val email: String? = "user@estudy247.com"

email?.let {
    println("Sending email to: $it")
    // this block only runs if email is not null
}

val noEmail: String? = null
noEmail?.let {
    println("This line never runs.")
}

Handling Nullable Collections

val items: List = listOf("Kotlin", null, "Android", null, "JVM")

// Filter out nulls
val nonNull: List = items.filterNotNull()
println(nonNull)   // [Kotlin, Android, JVM]

// Safe iteration
for (item in items) {
    println(item?.uppercase() ?: "MISSING")
}
// KOTLIN, MISSING, ANDROID, MISSING, JVM

Null Safety Decision Flowchart

You have a nullable value  →  val x: String?
              │
              ▼
    Does it need a default if null?
       YES → use Elvis (?:)
          x ?: "default"
       NO  → need to use the value safely?
          YES → use safe call (?.)
             x?.length
          NO  → are you 100% sure it's not null?
             YES → use !! (risky)
             NO  → use let { } block

Leave a Comment

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