liveBook · Manning

Nullable type

As explained in Kotlin in Action, 2E

A nullable type is a type whose values may include null and whose unsafe operations are restricted by the type system.

A nullable type makes absence explicit. In Kotlin, ordinary types such as String are non-nullable; add ? to permit null, as in String?. The compiler then rejects ordinary member calls on that value, turning many potential NullPointerExceptions into compile-time errors rather than runtime crashes. section 7.1 section 7.2

Listing 7.1 Handling null values using if checks
fun strLenSafe(s: String?): Int =
    if (s != null) s.length else 0   #1
 
fun main() {
    val x: String? = null
    println(strLenSafe(x))
    // 0
    println(strLenSafe("abc"))
    // 3
}

A null check narrows a String? to a usable non-null String within the true branch. This direct form is useful when both the null and non-null cases need distinct behavior. section 7.2

Choose a nullable type when null is a meaningful possible value, then handle that possibility explicitly:

  • Use a safe call (?.) to access a property or invoke a method only when the receiver is non-null. section 7.13
  • Use the Elvis operator (?:) to supply a fallback, return, or throw when an expression is null. section 7.13
  • Use ?.let { ... } to run a lambda only for a non-null value; its parameter is then non-nullable. section 7.13
  • Reserve !! for a proven invariant: it promises non-nullness but throws an exception if the promise is wrong. section 7.13

Nullability is part of the type, not a wrapper. A nullable and non-nullable value have the same runtime representation, with essentially no runtime overhead beyond limited generated checks. For nullable primitive types such as Int?, JVM interoperability uses the corresponding boxed type because null requires a reference. section 7.3 section 8.1.3

Absent age versus absent collection

List<Int?> means the list exists but individual numbers may be absent. List<Int>? means the list itself may be absent while its elements are non-null. List<Int?>? expresses both possibilities. After filterNotNull(), the resulting collection has a non-nullable element type, avoiding repeated handling later. section 8.2.1

Generics are a notable edge case: an unconstrained type parameter T may be nullable, even without ?. Add an upper bound such as T : Any when an API must reject nullable type arguments. Java boundaries need extra care: Kotlin may treat Java types as nullable or non-nullable, and a non-null declaration can cause a generated assertion if Java passes null. section 7.11 section 7.12.2

Nullable receiver extensions can centralize absence handling. For example, String?.isNullOrBlank() can be called without a safe call because the extension itself accepts a null receiver and checks it deliberately. section 7.10

How Kotlin in Action, 2E covers it

How deep it goes
Develops syntax, checks, operators, collections, generics, nullable extensions, primitive representation, and Java overrides.
Examples
Uses string-length functions, optional ages, parsed-number lists, nullable receiver extensions, and Java interface implementations.
What it assumes
Assumes basic Kotlin type and function syntax while introducing nullability from explicit String and String? examples.
What you can do after
Apply nullable types and Kotlin null-handling operators to prevent unsafe dereferences and model absent values.
How it connects
Connects safe calls, the Elvis operator, let, generics, collections, extension functions, and Java interoperability.

Also explained in

Compare how 3 books explain nullable type →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.