Kotlin eliminates NullPointerException at compile time by distinguishing nullable and non-nullable types.
Nullable types
var name: String = "Kotlin" // non-null — cannot hold null
// name = null // compile error
var nullable: String? = null // nullable — can hold null
nullable = "hello" // okSafe calls
val nullable: String? = null
// Safe call operator ?.
val length: Int? = nullable?.length // null — no NPE
// Chain safe calls
val user: User? = null
val city: String? = user?.address?.city // null — any null in chain short-circuitsElvis operator
// Provide a default when null
val length = nullable?.length ?: 0 // 0 if null
val name = nullable ?: "default" // "default" if null
// Elvis with throw
val value = nullable ?: throw IllegalArgumentException("required")
// Elvis with return
val value = nullable ?: returnNon-null assertion
// !! throws NPE if null — use sparingly
val length = nullable!!.length // NPE if null
// Prefer safe calls or let insteadSafe casts
// as? returns null on failure instead of ClassCastException
val x: Any = "hello"
val num: Int? = x as? Int // null
val str: String? = x as? String // "hello"let, also, run, apply, with — scope functions for null safety
// let — execute block only if non-null
nullable?.let {
println(it.length) // it is String, not String?
}
// also — perform side effect, return original
nullable?.also {
println("logging: $it")
}
// Multiple null checks
val a: String? = "hello"
val b: String? = "world"
a?.let { first ->
b?.let { second ->
println("$first $second") // only runs if both non-null
}
}Collections and null filtering
val list: List<String?> = listOf("a", null, "b", null, "c")
list.filterNotNull() // [a, b, c] — removes nulls
list.mapNotNull { it?.uppercase() } // [A, B, C] — maps and removes nullsrequire, check, error — fail-fast assertions
// require — validates arguments (throws IllegalArgumentException)
fun greet(name: String?) {
requireNotNull(name) // throws if null
require(name.length > 0) { "name cannot be empty" }
println("Hello, $name") // smart-cast to String
}
// check — validates state (throws IllegalStateException)
fun process() {
check(isInitialized) { "not initialized" }
}
// error — throws IllegalStateException with a message
fun fail(message: String): Nothing = throw IllegalStateException(message)Lateinit
// For late initialization of non-nullable properties
class MyService {
lateinit var repository: Repository // will be set later
fun init(repo: Repository) {
repository = repo
}
}
// Check if initialized
if (service::repository.isInitialized) {
service.repository.doSomething()
}Nullable types in generics
// T? allows null regardless of T
fun <T> firstOrNull(list: List<T>): T? {
return list.firstOrNull()
}
// Platform types from Java — treat as nullable
val javaString: String? = JavaClass.getName() // Java returns may be null