The not-null assertion !! turns a T? into a T by force, throwing a NullPointerException when the value is missing. It tells the compiler "trust me" and brings back the very crash null safety removes:
data class Book(val id: Int, val title: String)
val catalog = listOf(Book(1, "The Quiet Harbor"))
fun find(id: Int): Book? = catalog.find { it.id == id }
fun main() {
println(find(1)!!.title) // fine: book 1 exists
try { println(find(99)!!.title) } catch (e: NullPointerException) { println(e) }
val book = checkNotNull(find(99)) { "Book #99 is missing from the catalog" }
println(book.title)
}The Quiet Harbor java.lang.NullPointerException Exception in thread "main" java.lang.IllegalStateException: Book #99 is missing from the catalog at BangKt.main(bang.kt:7) at BangKt.main(bang.kt)
A bare !! failure has no message. When a value must exist, say why: checkNotNull(x) { "..." } throws an IllegalStateException with your message (requireNotNull() an IllegalArgumentException, for arguments). Better still, handle absence with ?. and ?:. The open-source linter detekt (https://github.com/detekt/detekt 7,073 ) flags every !! through its UnsafeCallOnNullableType rule, on by default. For a property set after construction, such as one filled by a dependency-injection framework, lateinit var beats a nullable type plus !!.