liveBook · Manning

Non-nullable type

As explained in Kotlin in Action, 2E

A non-nullable type is a Kotlin type whose values are not permitted to be null by the type system.

A non-nullable type is Kotlin’s default: `String`, `Int`, and `MyType` cannot hold `null`. Add `?` only when absence is a valid value, as in `String?`. This distinction prevents code from treating a possibly absent value as though it were ready to use. section 7.2 section 7.3

Require a present string

```kotlin fun strLen(s: String) = s.length fun main() { strLen(null) // error } ``` Because `s` is non-nullable, callers cannot pass `null`, and `length` needs no null check. A `String?` cannot be assigned to `String` or passed where `String` is required. After checking `s != null`, Kotlin treats a nullable value as non-nullable within that checked scope. section 7.2

Use the type distinction to make null handling explicit:

  • Declare a parameter or property non-nullable when it must have a value; provide an initializer for non-nullable properties unless delayed initialization is appropriate. section 7.2 section 7.9
  • Handle `T?` before calling members or passing it to a non-nullable parameter, using an `if` check or a safe-call with `let`. section 7.2 section 7.8
  • Treat `T` as usable where `T?` is expected, but not the reverse: a non-null type is a subtype of its nullable version. section 11.3.2
  • Constrain a generic parameter with `<T : Any>` when substitutions must be non-null; unconstrained `T` can be nullable. section 11.1.4 section 7.11

Pass a nullable value safely

```kotlin fun sendEmailTo(email: String) { println("Sending email to $email") } val email: String? = "yole@example.com" email?.let { sendEmailTo(it) } ``` The safe call runs `let` only when `email` is present. Inside the lambda, `it` is suitable for `sendEmailTo`, which requires a non-nullable `String`. section 7.8

Nullable and non-nullable values use the same runtime objects rather than wrapper objects, with little runtime overhead beyond generated intrinsic checks. The main protection is therefore at compile time: disallowed operations and unsafe flows are rejected before execution. section 7.3

Listing 7.19 Implementing the Java interface with different parameter nullability
class StringPrinter : StringProcessor {
   override fun process(value: String) {
       println(value)
   }
}

class NullableStringPrinter : StringProcessor {
   override fun process(value: String?) {
       if (value != null) {
           println(value)
       }
   }
}

Compare two Kotlin implementations of the same Java interface: one accepts `String`, and one accepts `String?`. Choosing `String` causes generated assertions for calls arriving from Java; Java passing `null` then triggers an exception even if the implementation does not read the parameter. section 7.12.2

`lateinit var` is an escape hatch for framework-managed setup: it keeps a property non-nullable without constructor initialization. It shifts responsibility to initialization order; reading the property too early produces a specific uninitialized-property exception. This is useful for patterns such as JUnit setup or Java dependency injection. section 7.9

How Kotlin in Action, 2E covers it

How deep it goes
Explains declarations, smart casts, subtyping, generics, delayed properties, and Java overrides without detailing generated checks further.
Examples
Uses string-length functions, email sending, generic processors, Java interface overrides, and JUnit-style service setup.
What you can do after
Apply it by declaring required values non-nullable and converting nullable values only after an explicit safe path.
How it connects
Connects nullable types, safe calls, Elvis operator, non-null assertions, let, platform types, generics, and subtyping.

Also explained in

Compare how 2 books explain non-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.