Sparround

val/var, null safety & the type system

Kotlin's type system separates nullable and non-nullable types: a String can never be null, a String? can. This catches most of Java's NullPointerExceptions at compile time.

Variable declarations:

  • val — a read-only reference: assigned once, never reassigned. It does not mean the object is immutable — val list = mutableListOf(1) still lets you mutate the list.
  • var — a mutable reference.

A frequent interview probe: "does val mean immutable?" The correct answer: val makes the reference immutable, not the object.

OperatorWhat it doesWhen to use
`?.` (safe call)Returns null if the receiver is nullThe default — anywhere null is possible
`?:` (Elvis)Provides a fallback when nullFor defaults or early returns
`!!` (not-null assertion)Throws NPE if nullAlmost never — considered a code smell
`lateinit var`A non-null var assigned laterFields initialized late via DI/lifecycle
`by lazy { }`A val computed on first accessExpensive values needed once

Interview trap: lateinit works only with var and reference types, while lazy only with val. Accessing an uninitialized lateinit throws UninitializedPropertyAccessException — checkable via ::field.isInitialized. In banking codebases !! is usually blocked in code review.

🛠 Practice task

In Kotlin Playground write a small Account model: val fields, one nullable (primaryCard: Card?).

  • Write one line using !! and crash it on purpose with a null — read the stack trace.
  • Rewrite that line with ?. + ?:.
  • Declare a lateinit var, read it before assignment to see the exception, then guard it with ::field.isInitialized.

Done when: you can explain each of the three outcomes in one sentence.

📚 Sources and documentation