Kotlin Cheatsheet
Null Safety
Use this Kotlin reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Nullable types
val name: String = "Ada" // never null val nickname: String? = null // nullable — must be handled before use
| Operator | Meaning | Example |
|---|---|---|
?. | safe call — evaluates to null if receiver is null | user?.email?.length |
?: | Elvis — fallback when left side is null | nickname ?: "anon" |
!! | assert non-null, throws NullPointerException if null | cache!!.size |
as? | safe cast — null instead of ClassCastException | x as? String |
?.let { } | run block only when non-null | id?.let { load(it) } |
!! is a code smell outside tests and truly-impossible cases — prefer ?:, ?.let, or requireNotNull.
Idiomatic patterns
// run only when non-null; `it` is smart-cast to non-null inside user?.let { send(it.email) } // Elvis with early exit — throw / return are expressions val id = request.id ?: return val cfg = load() ?: error("config missing") // chain with default val city = user?.address?.city ?: "unknown" // null-safe equality needs no operators: == handles null if (a == b) { } // true when both null
Preconditions
| Function | Throws | Use for |
|---|---|---|
require(cond) { "msg" } | IllegalArgumentException | validating arguments |
requireNotNull(x) { "msg" } | IllegalArgumentException | non-null argument; returns non-null x |
check(cond) { "msg" } | IllegalStateException | validating internal state |
checkNotNull(x) | IllegalStateException | non-null state; returns non-null x |
error("msg") | IllegalStateException | unreachable branches |
fun process(order: Order?) { val o = requireNotNull(order) { "order required" } // o: Order check(o.items.isNotEmpty()) { "empty order" } }
Smart casts
fun describe(value: Any?): String { if (value == null) return "null" // value: Any from here on if (value is String) return "len=${value.length}" // auto-cast to String if (value !is Int) return "other" return "int=${value + 1}" // value: Int }
Smart casts work after is/!is/null checks on vals the compiler can prove stable (locals, private vals). For var properties, copy to a local first: val v = this.field.
lateinit
class Service { lateinit var repo: Repo // var, non-null type, no primitive types fun ready() = ::repo.isInitialized fun use() { repo.save() // throws UninitializedPropertyAccessException if unset } }
Use lateinit for DI/framework-injected properties. For computed-once values prefer val x by lazy { ... } instead.
Nulls in collections
val xs: List<Int?> = listOf(1, null, 3) xs.filterNotNull() // [1, 3] List<Int> xs.mapNotNull { it?.times(2) } // map + drop nulls strings.firstNotNullOfOrNull { it.toIntOrNull() } // first parse that succeeds listOfNotNull(a, b, c) // builds list skipping null args map.getOrDefault(key, 0); map[key] ?: 0
Platform types (Java interop)
Values from un-annotated Java APIs have unknown nullability (String!). The compiler lets you treat them either way — crashes surface at runtime. Pin the type at the boundary:
val header: String? = javaRequest.getHeader("X-Id") // choose nullable explicitly