Null Safety Patterns
Let Scope
Run a small block only when a nullable value is present.
let
`let` can transform a present value while safe calls and Elvis provide the null path.
Let Scope
LetScope.kt
Replay: real traced execution (multi-file project)
fun main() {
val raw: String? = " oak "
val cleaned = raw?.let { value ->
value.trim().toUpperCase()
} ?: "EMPTY"
println("raw=${raw ?: "none"}")
println("cleaned=$cleaned")
}
fun main() {
val raw: String? = null
val cleaned = raw?.let { value ->
value.trim().toUpperCase()
} ?: "EMPTY"
println("raw=${raw ?: "none"}")
println("cleaned=$cleaned")
}
fun main() {
val raw: String? = " pine "
val cleaned = raw?.let { value ->
value.trim().toUpperCase()
} ?: "EMPTY"
println("raw=${raw ?: "none"}")
println("cleaned=$cleaned")
}
raw ← oak , cleaned ← OAK
1fun main() {2 val raw→ oak : String? = " oak " //@raw=null, " pine "3 val cleaned→ OAK = raw oak ?.let { value ->4 value.trim().toUpperCase()5 } ?: "EMPTY"67 println("raw=${raw oak ?: "none"}")8 println("cleaned=$cleanedOAK")9}outputraw= oak cleaned=OAK
raw ← null, cleaned ← EMPTY
1fun main() {2 val raw→ null: String? = null3 val cleaned→ EMPTY = rawnull?.let { value ->4 value.trim().toUpperCase()5 } ?: "EMPTY"67 println("raw=${rawnull ?: "none"}")8 println("cleaned=$cleanedEMPTY")9}outputraw=none cleaned=EMPTY
raw ← pine , cleaned ← PINE
1fun main() {2 val raw→ pine : String? = " pine "3 val cleaned→ PINE = raw pine ?.let { value ->4 value.trim().toUpperCase()5 } ?: "EMPTY"67 println("raw=${raw pine ?: "none"}")8 println("cleaned=$cleanedPINE")9}outputraw= pine cleaned=PINE
Let or Empty
rawmay hold padded text ornull.raw?.let { ... }runs the block only for present text.- Inside
let, the text is trimmed and uppercased. - If
rawis null, Elvis returns"EMPTY". |rawvalue | Flow |cleaned| | --- | --- | --- | |" oak "| runlet|OAK| |null| skiplet|EMPTY|
Exercise: LetScope.kt
Use let to trim and uppercase nullable text, then use EMPTY when the text is null