When writing code in Kotlin,
you may encounter an error called
“Only safe (?.) or non-null asserted (!!.) calls are allowed”.
This error occurs when you try to access a property or function
in the normal way on a nullable value that may be null.
In Kotlin,
types that allow null and types that do not allow null are clearly distinguished,
so when using nullable types,
you need to write code that takes the null case into account.
This article introduces the causes to check and the basic solutions
when “Only safe (?.) or non-null asserted (!!.) calls are allowed”
appears in Kotlin.
- What Is “Only safe (?.) or non-null asserted (!!.) calls are allowed”?
- Cause 1: Directly Accessing a Nullable Type
- Using the Safe Call Operator “?.”
- Checking for Null Before Accessing the Value
- Using the Elvis Operator “?:” to Specify a Value for Null
- Using “!!” to Treat a Value as Non-Null
- Cause 2: The Function Return Value Is Nullable
- Cause 3: An Android API Return Value Is Nullable
- Cause 4: A Value Obtained with findViewById or Similar Methods Is Nullable
- Cause 5: A Value Obtained from a Map Is Nullable
- Cause 6: The Result Becomes Nullable During a Safe Call
- Using let to Process the Value Only When It Is Not Null
- Excluding Null with an Early return
- Check Whether the Value Needs to Be Nullable
- Difference Between “?.” and “!!”
- Order of Checks When “Only safe (?.) or non-null asserted (!!.) calls are allowed” Appears
- Check the Specific Error Location
- Summary
What Is “Only safe (?.) or non-null asserted (!!.) calls are allowed”?
“Only safe (?.) or non-null asserted (!!.) calls are allowed”
is an error indicating that a normal property access or function call
is being performed on a value that may be null.
For example, suppose you have the following code.
val text: String? = null
println(text.length)
In this code,
text is defined as a
String? type.
Because String? may be null,
you cannot directly access a property
as in text.length.
If it is null,
length cannot be accessed,
so Kotlin detects this as an error at compile time.
When accessing a nullable value,
use the safe call operator ?.,
a null check,
the Elvis operator ?:,
or another method to write code that takes the null case into account.
Cause 1: Directly Accessing a Nullable Type
The most basic cause is using
. to directly access
a variable of a nullable type.
val name: String? = "Taro"
println(name.length)
name contains
"Taro",
but because its type is String?,
it may be null.
Therefore,
Kotlin does not allow normal access using
..
Using the Safe Call Operator “?.”
The basic way to safely access a nullable value
is to use the safe call operator
?..
val text: String? = null
println(text?.length)
If text is not null,
length is obtained.
On the other hand,
if text is null,
length is not accessed,
and the result of the entire expression becomes null.
When accessing properties or functions of a nullable type,
the basic approach is to first check whether the operation
can be handled safely with ?..
Checking for Null Before Accessing the Value
If you want to process the value only when it is not null,
you can check for null before accessing it.
val text: String? = "Hello"
if (text != null) {
println(text.length)
}
Within a scope where
text != null is true,
Kotlin may treat text
as a non-null value.
This mechanism allows you to access
text.length
without using ?..
Using the Elvis Operator “?:” to Specify a Value for Null
If you want to use another value when a nullable value is null,
you can use the Elvis operator
?:.
val text: String? = null
val length = text?.length ?: 0
In this case,
if text is not null,
the length of the string is stored in length.
If it is null,
0 is used.
This can be used when you do not want to pass null
to later processing.
Using “!!” to Treat a Value as Non-Null
Kotlin has the
!! operator,
which forcibly treats a nullable value as non-null.
val text: String? = "Hello"
println(text!!.length)
In this case,
you are instructing Kotlin
to treat text as non-null.
However,
if the actual value is null,
an exception occurs at runtime.
val text: String? = null
println(text!!.length)
Using !! may allow you to avoid a compilation error,
but there is a possibility of a runtime error if the value is null.
Unless you are certain that the value is not null,
consider using a safe call or null check first.
Cause 2: The Function Return Value Is Nullable
Even if you have not declared a nullable variable yourself,
an error may occur because a function returns a nullable value.
fun getName(): String? {
return null
}
val name = getName()
println(name.length)
Because the return type of
getName() is
String?,
name may also be null.
When using a safe call,
write it as follows.
println(name?.length)
You can also specify a value to use when it is null.
println(name?.length ?: 0)
Cause 3: An Android API Return Value Is Nullable
In Android development,
API return values are often nullable.
For example,
when retrieving a string from an Intent with
getStringExtra(),
you need to consider the possibility that the value does not exist.
val name = intent.getStringExtra("name")
println(name.length)
If name may be null,
you cannot directly access length.
When using a safe call,
write it as follows.
println(name?.length)
If you want to use an empty string when the value is null,
you can also write it as follows.
val name: String = intent.getStringExtra("name") ?: ""
println(name.length)
Cause 4: A Value Obtained with findViewById or Similar Methods Is Nullable
Values obtained from Android Views or external APIs
may also be treated as nullable types.
If you access such a value directly,
the same error may appear.
If the value may not exist,
use a safe call or null check.
val view: View? = findViewById(R.id.sampleView)
view?.visibility = View.VISIBLE
In this case,
if view is null,
the visibility setting is not executed.
Cause 5: A Value Obtained from a Map Is Nullable
When retrieving a value from a Kotlin Map
using [] or a similar method,
the return value is nullable because the specified key may not exist.
val users = mapOf(
"user1" to "Taro"
)
val name = users["user1"]
println(name.length)
Because
users["user1"]
may be null,
directly accessing name results in an error.
When using a safe call,
write it as follows.
println(name?.length)
When using a default value,
you can also combine it with the Elvis operator.
println(name?.length ?: 0)
Cause 6: The Result Becomes Nullable During a Safe Call
When you use a safe call,
the result of that expression may also become nullable.
val text: String? = "Hello"
val length: Int? = text?.length
If text is null,
the result of text?.length is also null,
so length is treated as
Int?.
When using this value further,
you also need to take into account that it is nullable.
Using let to Process the Value Only When It Is Not Null
In Kotlin,
you can combine a safe call with
let
to execute processing only when the value is not null.
val text: String? = "Hello"
text?.let {
println(it.length)
}
If text is not null,
the processing inside let is executed.
If it is null,
the processing inside let is not executed.
Excluding Null with an Early return
When using a nullable value inside a function,
you can also end the processing first if the value is null.
fun showLength(text: String?) {
if (text == null) {
return
}
println(text.length)
}
Because the function returns first when the value is null,
text may be treated as a non-null value
in the subsequent processing.
You can also use the Elvis operator
to write this more concisely.
fun showLength(text: String?) {
val value = text ?: return
println(value.length)
}
Check Whether the Value Needs to Be Nullable
When an error occurs,
before adding a safe call,
it is also important to check whether the target variable
really needs to be nullable in the first place.
val name: String? = "Taro"
If this variable always has a value
and can never be null,
it may not need to be nullable.
val name: String = "Taro"
println(name.length)
In this case,
because name cannot be null,
you can access it using the normal ..
Rather than adding
?. everywhere just to avoid the error,
it is also important to check whether the value
really needs to be nullable.
Difference Between “?.” and “!!”
The error message displays
?. and
!!.,
but their behavior is very different.
text?.length
With ?.,
if the value is null,
the operation is not executed,
and null is returned as the result.
text!!.length
With !!,
the value is forcibly processed as if it were not null.
If the value is actually null,
an exception occurs at runtime.
If the value may be null,
it is safer to use
?. or a null check.
Use !! when you can reliably guarantee
that the value is not null.
Order of Checks When “Only safe (?.) or non-null asserted (!!.) calls are allowed” Appears
If you do not know the cause,
checking the following items in order
can make it easier to isolate the problem.
- Check the type of the variable where the error appears.
- Check whether
?is added after the type. - Check whether the value can actually be null.
- Check whether the operation can be handled with the safe call
?.. - Check whether you can access the value after performing a null check.
- Check whether you can specify a default value with the Elvis operator
?:. - Check whether you can use
letto process the value only when it is not null. - Check whether the return value of a function or Android API is nullable.
- Check whether the value needs to be nullable in the first place.
- Check whether
!!is being used to forcibly avoid the error.
Check the Specific Error Location
When resolving
“Only safe (?.) or non-null asserted (!!.) calls are allowed”,
check not only the property or function where the error appears,
but also whether the object before it is a nullable type.
Example:
val text: String? = null
println(text.length)
→ Since text is nullable, consider text?.length
val name = intent.getStringExtra("name")
println(name.length)
→ Check whether the return value of getStringExtra() may be null
val name = users["user1"]
println(name.length)
→ Check whether the value retrieved from the Map may be null
val text: String? = "Hello"
println(text!!.length)
→ Check whether you can truly guarantee that it will not be null
Summary
Kotlin’s
“Only safe (?.) or non-null asserted (!!.) calls are allowed”
is an error that occurs when you access a property or function
in the normal way on a nullable value that may be null.
In Kotlin,
non-null types and nullable types are clearly distinguished,
such as
String and
String?.
When the error appears,
first check whether the target variable or function return value
is a nullable type.
If the value may be null,
use the safe call operator ?.,
a null check,
the Elvis operator ?:,
let,
or another method to write processing that takes null into account.
Using !! allows you to forcibly treat the value as non-null,
but if the actual value is null,
an exception occurs at runtime.
Rather than simply adding
?. or !!
to eliminate the compilation error,
it is important to check why the value is nullable
and whether it can actually be null,
and then choose the appropriate processing method.
