# Non-Null Assertions

A second approach to the problem of nullable types is to have special knowledge that the reference in question isn’t null.

To make this claim, use the double exclamation point, !!, called the non-null assertion. If this looks alarming, it should: believing that something can’t be null is the source of most null-related program failures (the rest come from not realizing that a null can happen).

x!! means “forget the fact that x might be null—I guarantee that it’s not null.” x!! produces x if x isn’t null, otherwise it throws an exception:

// NonNullAssertions/NonNullAssert.kt
import atomictest.*

fun main() {
  var x: String? = "abc"
  x!! eq "abc"
  x = null
  capture {
    val s: String = x!!
  } eq "NullPointerException"
}

The definition val s: String = x!! tells Kotlin to ignore what it thinks it knows about x and just assign it to s, which is a non-nullable reference. Fortunately, there’s run-time support that throws a NullPointerException when x is null.

Ordinarily you won’t use the !! by itself, but instead in conjunction with a . dereference:

// NonNullAssertions/NonNullAssertCall.kt
import atomictest.eq

fun main() {
  val s: String? = "abc"
  s!!.length eq 3
}

If you limit yourself to a single non-null asserted call per line, it’s easier to locate a failure when the exception gives you a line number.

The safe call ?. is a single operator, but a non-null asserted call consists of two operators: the non-null assertion (!!) and a dereference (.). As you saw in NonNullAssert.kt, you can use a non-null assertion by itself.

Avoid non-null assertions and prefer safe calls or explicit checks. Non-null assertions were introduced to enable interaction between Kotlin and Java, and for the rare cases when Kotlin isn’t smart enough to ensure the necessary checks are performed.

If you frequently use non-null assertions in your code for the same operation, it’s better to use a separate function with a specific assertion describing the problem. As an example, suppose your program logic requires a particular key to be present in a Map, and you prefer getting an exception instead of silently doing nothing if the key is absent. Instead of extracting the value with the usual approach (square brackets), getValue() throws NoSuchElementException if a key is missing:

// NonNullAssertions/ValueFromMap.kt
import atomictest.*

fun main() {
  val map = mapOf(1 to "one")
  map[1]!!.toUpperCase() eq "ONE"
  map.getValue(1).toUpperCase() eq "ONE"
  capture {
    map[2]!!.toUpperCase()
  } eq "NullPointerException"
  capture {
    map.getValue(2).toUpperCase()
  } eq "NoSuchElementException: " +
    "Key 2 is missing in the map."
}

Throwing the specific NoSuchElementException gives you more useful details when something goes wrong.

  • -

Optimal code uses only safe calls and special functions that throw detailed exceptions. Only use non-null asserted calls when you absolutely must. Although non-null assertions were included to support interaction with Java code, there are better ways to interact with Java, which you can learn about in [Appendix B: Java Interoperability](javascript:void(0)).

Exercises and solutions can be found at www.AtomicKotlin.com.