0% found this document useful (0 votes)
21 views7 pages

Nullable Types and Non

Kotlin's type system distinguishes between nullable and non-nullable types to eliminate null pointer exceptions. For nullable types, Kotlin provides several ways to safely access members: 1) explicitly check for null; 2) use the safe call operator ?.; 3) use the Elvis operator ?: to return a non-null value if the left side is null. The !! operator can be used to force unwrapping but will throw an exception if null. Collections of nullable types can filter null values using filterNotNull().

Uploaded by

a7813010
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views7 pages

Nullable Types and Non

Kotlin's type system distinguishes between nullable and non-nullable types to eliminate null pointer exceptions. For nullable types, Kotlin provides several ways to safely access members: 1) explicitly check for null; 2) use the safe call operator ?.; 3) use the Elvis operator ?: to return a non-null value if the left side is null. The !! operator can be used to force unwrapping but will throw an exception if null. Collections of nullable types can filter null values using filterNotNull().

Uploaded by

a7813010
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

Nullable types and non-null types

Kotlin's type system is aimed at eliminating the danger of null references, also known as The Billion
Dollar Mistake.

One of the most common pitfalls in many programming languages, including Java, is that accessing
a member of a null reference will result in a null reference exception. In Java this would be the
equivalent of a NullPointerException, or an NPE for short.

The only possible causes of an NPE in Kotlin are:

 An explicit call to throw NullPointerException().


 Usage of the !! operator that is described below.
 Data inconsistency with regard to initialization, such as when:
o An uninitialized this available in a constructor is passed and used somewhere.
o A superclass constructor calls an open member whose implementation in the derived
class uses an uninitialized state.
 Java interoperation:
o Attempts to access a member of a null reference of a platform type;
o Nullability issues with generic types being used for Java interoperation. For example,
a piece of Java code might add null into a Kotlin MutableList<String>, therefore
requiring a MutableList<String?> for working with it.
o Other issues caused by external Java code.

In Kotlin, the type system distinguishes between references that can hold null (nullable references)
and those that cannot (non-null references). For example, a regular variable of type String cannot
hold null:
var a: String = "abc" // Regular initialization means non-null by default
a = null // compilation error

To allow nulls, you can declare a variable as a nullable string by writing String?:
var b: String? = "abc" // can be set to null
b = null // ok
print(b)

Now, if you call a method or access a property on a, it's guaranteed not to cause an NPE, so you can
safely say:

val l = a.length

But if you want to access the same property on b, that would not be safe, and the compiler reports an
error:

val l = b.length // error: variable 'b' can be null

But you still need to access that property, right? There are a few ways to do so.
Checking for null in conditions
First, you can explicitly check whether b is null, and handle the two options separately:

val l = if (b != null) b.length else -1


The compiler tracks the information about the check you performed, and allows the call to length
inside the if. More complex conditions are supported as well:
val b: String? = "Kotlin"
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}

Note that this only works where b is immutable (meaning it is a local variable that is not modified
between the check and its usage or it is a member val that has a backing field and is not
overridable), because otherwise it could be the case that b changes to null after the check.

Safe calls
Your second option for accessing a property on a nullable variable is using the safe call operator ?.
val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length) // Unnecessary safe call

This returns b.length if b is not null, and null otherwise. The type of this expression is Int?.

Safe calls are useful in chains. For example, Bob is an employee who may be assigned to a
department (or not). That department may in turn have another employee as a department head. To
obtain the name of Bob's department head (if there is one), you write the following:

bob?.department?.head?.name

Such a chain returns null if any of the properties in it is null.

To perform a certain operation only for non-null values, you can use the safe call operator together
with let:
val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
item?.let { println(it) } // prints Kotlin and ignores null
}

A safe call can also be placed on the left side of an assignment. Then, if one of the receivers in the
safe calls chain is null, the assignment is skipped and the expression on the right is not evaluated at
all:
// If either `person` or `person.department` is null, the function is not
called:
person?.department?.head = managersPool.getManager()

Elvis operator
Elvis operator (?:) is used to return the not null value even the conditional expression is null. It is
also used to check the null safety of values.

In some cases, we can declare a variable which can hold a null reference. Suppose that a variable str
which contains null reference, before using str in program we will check it nullability. If variable str
found as not null then its property will use otherwise use some other non-null value.

var str: String? = null

var str2: String? = "May be declare nullable string"

In above code, the String str contains a null value, before accessing the value of str we need to
perform safety check, whether string contain value or not. In conventional method we perform this
safety check using if ... else statement.

var len1: Int = if (str != null) str.length else -1

var len2: Int = if (str2 != null) str.length else -1

fun main(){

var str: String? = null


var str2: String? = "May be declare nullable string"
var len1: Int = if (str != null) str.length else -1
var len2: Int = if (str2 != null) str2.length else -1
println("Length of str is ${len1}")
println("Length of str2 is ${len2}")
}
Output:
Length of str is -1
Length of str2 is 30

Kotlin provides advance operator known as Elvis operator(?:) which return the not null value even
the conditional expression is null. The above if . . . else operator can be expressed using Elvis
operator as bellow:

var len1: Int = str?.length ?: -1


var len2: Int = str2?.length ?: -1
Elvis operator returns expression left to ?: i.e -1. (str?. length) if it is not null otherwise it returns
expression right to (?:)i.e(-1). The expression right side of Elvis operator evaluated only if the left
side returns null.
Kotlin Elvis Operator example
fun main(){
var str: String? = null
var str2: String? = "May be declare nullable string"
var len1: Int = str ?.length ?: -1
var len2: Int = str2 ?.length ?: -1

println("Length of str is ${len1}")


println("Length of str2 is ${len2}")
}
Output:
Length of str is -1
Length of str2 is 30

As Kotlin throw and return an expression, they can also be used on the right side of the Elvis
operator. This can be used for checking functional arguments:

funfunctionName(node: Node): String? {


val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ...
}
Kotlin Elvis Operator using throw and return expression
fun main(){
val fruitName: String = fruits()
println(fruitName)
}
fun fruits(): String{
val str: String? ="abc"
val strLength: Int = if(str!= null) str.length else -1
val strLength2: Int = str?.length ?: -1
var string = "str = $str\n"+
"strLength = $strLength\n"+
"strLength2 = $strLength2\n\n"

fun check(textOne: String?, textTwo: String?): String?{


val textOne = textOne ?: return null
val textTwo = textTwo ?: IllegalArgumentException("text exception")

return "\ntextOne = $textOne\n"+


"textTwo = $textTwo\n"
}
string += "check(null,\"mango\") = ${check(null,"mango")}\n" +
"check(\"apple\",\"orange\") = ${check("apple","orange")}\n"
return string
}
Output:
str = abc
strLength = 3
strLength2 = 3

check(null,"mango") = null
check("apple","orange") =
textOne = apple
textTwo = orange

When you have a nullable reference, b, you can say "if b is not null, use it, otherwise use some non-
null value":

val l: Int = if (b != null) b.length else -1

Instead of writing the complete if expression, you can also express this with the Elvis operator ?::

val l = b?.length ?: -1

If the expression to the left of ?: is not null, the Elvis operator returns it, otherwise it returns the
expression to the right. Note that the expression on the right-hand side is evaluated only if the left-
hand side is null.

Since throw and return are expressions in Kotlin, they can also be used on the right-hand side of
the Elvis operator. This can be handy, for example, when checking function arguments:

fun foo(node: Node): String? {


val parent = node.getParent() ?: return null
val name = node.getName() ?: throw IllegalArgumentException("name expected")
// ...
}

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. You can write b!!, and this will return a non-
null value of b (for example, 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 won't appear
out of the blue.
Safe casts
Regular casts may result in a ClassCastException if the object is not of the target type. Another
option is to use safe casts that return null if the attempt was not successful:

val aInt: Int? = a as? Int

Collections of a nullable type


If you have a collection of elements of a nullable type and want to filter non-null elements, you can
do so by using filterNotNull:

val nullableList: List<Int?> = listOf(1, 2, null, 4)


val intList: List<Int> = nullableList.filterNotNull()

You might also like