Kotlin provides significantly improved support for nullable (and non-nullable) types.
These are all the language and Kotlin library features that help support working with nullable types:
Non-nullable type declaration:
var a: String = "abc"
Nullable type declaration:
var b: String? = "abc"
Explicit null check (with else):
val l = if (b != null) b.length else -1
Note that 'smart-casting' means that within the if
block the type of object becomes non-nullable.
Even without smart-casting, the equality (==
) and inequality (!=
) operators are null-tolerant, e.g. returning false
for an equality test for a null object (unless, of course, the comparison value is also null
).
Thus the following is perfectly safe for a nullable type:
val myNullable: String? = null
if( myNullable != "Hello") println( "Success!!!")
Safe calls return the property/method if the object is not null, and null otherwise, and can be chained:
bob?.department?.head?.name
Substituting default values with Elvis:
return nullableVal ?: defaultVal
Another instance:
val l = b?.length ?: -1
Force a NullPointerException
to be thrown if nullable value is null:
val l = b!!.length
Cast to the specific type, or null, without failing:
val aInt: Int? = a as? Int
Only execute a code block for a non-null instance using a variation of the .let
operation:
myVal?.let {
it.addInterest()
}
Declare a collection that allows null types:
val nullableList: List<Int?> = listOf(1, 2, null, 4)
Remove nulls and convert to a non-nullable collection:
val intList: List<Int> = nullableList.filterNotNull()
In some situations we want the returned value to be non-null on;y in some situations, and null otherwise. The .takeIf
and .takeUnless
can be useful in reducing repetition. E.g.
return x.takeIf { it.isValid() }
or
return x.takeUnless { it.isError() }