kotlinintermediate
Null Safety — Advanced Patterns
Master null safety in Kotlin: chaining, smart casts, safe builders, orElse patterns, and nullable collections.
kotlinPress ⌘/Ctrl + Shift + C to copy
data class Address(val city: String?, val zip: String?)
data class Company(val name: String, val address: Address?)
data class Person(val name: String, val company: Company?, val tags: List<String>? = null)
// Extension for chaining
fun <T> T?.orElse(default: T): T = this ?: default
fun <T> T?.orThrow(message: () -> String): T = this ?: throw NoSuchElementException(message())
fun <T> T?.ifPresent(action: (T) -> Unit): T? { if (this != null) action(this); return this }
// Null-safe operations
fun String?.isNullOrShort(maxLength: Int = 3): Boolean = this == null || this.length <= maxLength
fun main() {
// Deep null-safe chaining
val person = Person(
"Alice",
Company("AcmeCorp", Address("New York", "10001"))
)
val nullPerson = Person("Bob", null)
// Safe call chain
val city = person.company?.address?.city
println("City: $city")
val noCity = nullPerson.company?.address?.city
println("No city: $noCity") // null
// Elvis operator
val displayCity = nullPerson.company?.address?.city ?: "Unknown"
println("Display: $displayCity")
// Elvis with throw
try {
val requiredCity = nullPerson.company?.address?.city
?: throw IllegalStateException("City is required")
} catch (e: Exception) {
println("Error: ${e.message}")
}
// Elvis with return (in real functions)
fun processCity(p: Person): String {
val c = p.company ?: return "No company"
val addr = c.address ?: return "No address"
val city = addr.city ?: return "No city"
return "Processing: $city"
}
println(processCity(person))
println(processCity(nullPerson))
// let for null-safe transformations
val zip: String? = person.company?.address?.zip
zip?.let { println("ZIP: $it") }
// Chained let
person.company?.address?.city?.let { city ->
println("Uppercase city: ${city.uppercase()}")
}
// also for side effects
val result = person.company?.also {
println("Found company: ${it.name}")
}?.address?.also {
println("Found address in: ${it.city}")
}
// run for scoped computation
val summary = person.company?.run {
"$name at ${address?.city ?: "unknown location"}"
} ?: "Unemployed"
println("Summary: $summary")
// takeIf / takeUnless
val validZip = zip?.takeIf { it.length == 5 }
println("Valid ZIP: $validZip")
val name: String? = " "
val cleanName = name?.takeUnless { it.isBlank() }
println("Clean name: $cleanName") // null
// Nullable collections
val tags: List<String>? = person.tags
val tagCount = tags?.size ?: 0
val firstTag = tags?.firstOrNull() ?: "none"
println("Tags: count=$tagCount, first=$firstTag")
// orEmpty for nullable collections
val safeTags = tags.orEmpty()
println("Safe tags: $safeTags")
// filterNotNull
val mixed: List<String?> = listOf("a", null, "b", null, "c")
val clean: List<String> = mixed.filterNotNull()
println("Filtered: $clean")
// mapNotNull
val numbers = listOf("1", "abc", "3", "xyz", "5")
val parsed = numbers.mapNotNull { it.toIntOrNull() }
println("Parsed: $parsed")
// Custom extensions
val value: String? = "Hello"
value.ifPresent { println("Value present: $it") }
val withDefault = (null as String?).orElse("default")
println("With default: $withDefault")
}Use Cases
- Safe navigation through nested nullable objects
- Defensive API data handling
- Nullable collection processing
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
kotlinbeginner
Null Safety — Elvis, Safe Call, and let
Master Kotlin null safety: safe calls, Elvis operator, let/also scoping, and smart casts.
Best for: Safe navigation through nullable chains
#kotlin#null-safety
kotlinbeginner
Scope Functions — let, run, apply, also, with
Master Kotlin scope functions: when to use let, run, apply, also, and with for concise code.
Best for: Object initialization and configuration
#kotlin#scope-functions
kotlinbeginner
Enum Classes — Advanced Patterns
Use Kotlin enum classes with properties, methods, interfaces, and companion utilities.
Best for: Type-safe constant sets with behavior
#kotlin#enum
kotlinbeginner
Destructuring Declarations
Destructure objects into variables: data classes, maps, pairs, and custom componentN operators.
Best for: Clean variable extraction from complex objects
#kotlin#destructuring