Consider the following code:
Example
fun main(args: Array<String>) {
maybeWriteMessage()
}
fun maybeWriteMessage(message: String? = null) {
writeMessage(message!!)
}
fun writeMessage(message: String) {
println("Hello World")
}
Output
Exception in thread "main" kotlin.KotlinNullPointerException at
com.series0ne.ApplicationKt.maybeWriteMessage(Application.kt:8) at
com.series0ne.ApplicationKt.maybeWriteMessage$default(Application.kt:7)
at com.series0ne.ApplicationKt.main(Application.kt:4)
This is because I'm passing message!!
(null, damn it!) to a non-nullable parameter, however the parameter is never accessed.
Question
Why does Kotlin forcibly throw KotlinNullPointerException
even when the null reference isn't accessed?
message: String?
is indicating that message
may or may not be null
.
Since your function maybeWriteMessage
has a default value of null
for message
and you are calling maybeWriteMessage()
without specifying message
- the default value (null
) will be used when calling writeMessage(message!!)
.
As written in the documentation the !!
-operator throws an exception when the value is null
.
One way to trigger writeMessage
safely would be to use .let
:
fun maybeWriteMessage(message: String? = null) {
message?.let { nonNullMessage ->
writeMessage(nonNullMessage)
}
}
Operator !!
throws an KotlinNullPointerException
if message
is null.
You can read about it here:
https://kotlinlang.org/docs/reference/null-safety.html#the--operator
In the following code:
fun maybeWriteMessage(message: String? = null) {
writeMessage(message!!)
}
you're asserting that the nullable parameter message
is not null by using !!
(the not-null assertion operator). If message
is null though, this will throw a null pointer.
TL;DR: Do not use !!
unless you exactly know what you're doing. There's almost always a better way.
The !! Operator
The third option is for NPE-lovers: the not-null assertion operator
(!!) converts any value to a non-null type and throws an exception if
the value is null. We can write b!!, and this will return a non-null
value of b (e.g., a String in our example) or throw an NPE if b is
null:
val l = b!!.length
Thus, if you want an NPE, you can have it, but you have to ask for it
explicitly, and it does not appear out of the blue.
From the documentation:
The !! Operator
The third option is for NPE-lovers: the not-null
assertion operator (!!
) converts any value to a non-null type and
throws an exception if the value is null. We can write b!!
, and this
will return a non-null value of b
(e.g., a String
in our example) or
throw an NPE if b
is null:
val l = b!!.length
Thus, if you want an NPE, you can have it, but you
have to ask for it explicitly, and it does not appear out of the blue.
So regardless of whether your function uses the parameter or not, by using message!!
, you are explicitly asking for a NPE.