I am sure you have heard that with Kotlin you won’t get NullPointerException, Well that’s not 100% true, It is just difficult to get one, and by getting one I mean you have to ask for it:D.
Nullable Types
Let’s start by trying to make a string null.
val str : String = null
this won’t work and the compiler will give an error saying, “Null cannot be a value of a non-null type String”, What does that mean?
well, Kotlin has what’s called nullable types, which means that you have to ALLOW the compiler to assign null to this string by adding ‘?‘ at the end of it so it will look like this
val str : String? = null
and that will work, but the problem is that the compiler will block you from calling nearly any method without checking if null or not (super safe ha?)
The Safe Call Operator
Let’s say we want to call str.toUpperCase(), this won’t work without doing a check
val str : String? = null if(str != null) { str.toUpperCase() }
but that is just not what Kotlin would do right? It just wants you to save time!, so Kotlin has what’s called The Safe Call Operator, which will work exactly like that if code we wrote up
val str : String? = null str?val str : String? = null()
it says if str is not null, the call the toUpperCase method, other than that it Will just return the String ‘null’ NOT a null string!
Let me show you how handy this operator is, as a Java developer I usually find myself doing this
if(Branch !=null) { Address address = Branch.getAddress(); if (address !=null) { Country country = address.getCountry(); if(country != null) { String countryCode = country.getCountryCode(); } } }
If we wanted to use the same code in Kotlin, The Safe Call Operator will make it way much shorter
val countryCode :String? = bankBranch?.address?.country?.countryCode
Pretty cool right?
The Elvis Operator ?:
With Kotlin’s Elvis Operator ‘?:‘, you can assign a default value to your variable if it is null
val str2 = str ?: "This is the default value"
what will this code do is that if the str is null, it will assign a default value instead of returning null, so str2 definitely won’t be null, that’s why we don’t need to say val str2 : String because the compiler knows 100% that this is going to be a String not Null.
which is equal to this code
if (str == null) { str2 = "This is the default value" } else { str2 = str }
we can also use it in the Branch example we did like this
val whatever = Branch?.address?.country ?: "Nop"
which will return the text “Nop” if any of Brach or address or country is null.
The safe Cast Operator
Let’s say we want to cast an array of integers to a string (which should throw a NullPointerException )
val something: Any = arrayOf(1, 2, 3, 4) val str3 = something as? String println(str3)
BUT again, Kotlin got our backs and it just evaluates it to null instead of throwing an exception.
Non-Null Assertion
In some cases, you are 100% sure this string isn’t null but the compiler still forces you to use the safe call operator, but you don’t want to check (this might be the case when you are debugging and you WANT to get an exception to fix your code).
we will be using the non-null assertion, ‘!!‘
val str: String? = "This isn't null" val str4 = str!!.toUpperCase()
which will then force the compiler to allow you to use all of the methods without checking if the str is null or not.
KoltinNullPoniterException
Let’s say we asked for a null to be thrown by using the !! operator, Kotlin will through the error as KoltinNullPoniterException, but there is a tiny trick here.
For example:
package besho.c_od_e.com fun main(args: Array<String>) { val str : String? = null val str2 = str!! val str3 - str2.toUpperCase() }
this will through the KoltinNullPoniterException, BUT the error will be shown at line 6, which we assumed it will happen at line 7 because that is where we called toUpperCase method on a null String!
what happened is that the exception will be thrown where we used Assertion, so when we make the assertion, the compiler will check whether the assertion is true, if it is not it will throw an exception.
so the exception we get kinda doesn’t give us information on what caused it, so you don’t want to do this:
val countryCode = Branch!!.address!!.country!!
because you can’t know which one is null since you will get only the line number and that’s it!
Functions and Nullable Types
If we created a function and it is expecting a non-nullable variable, you can’t pass a nullable one, since Kotlin handles them as different types.
Like this
fun printText(text: String) { println(text) }
If we tried to pass this variable
val str: String? = "This isn't null" printText(str)
we will get an error because str is a nullable string and the function is expecting a non-nullable one.
That will cause a problem especially since we sometimes use libraries which we didn’t type its functions, and they might be expecting a non-nullable but in our code we just want the string to be nullable and so we can’t just change it to fit the function right?
So there are 2 ways to call that function
First one is to use the Non-Null Assertion like this
val str: String? = "This isn't null" printText(str!!)
which means that you are telling the compiler that I am 100% sure this isn’t null and so it will let you call that function, but what if it IS null and that function doesn’t check if it’s null or not?
this is why we don’t use this and use what’s called ‘The Let Function’.
The Let Function
The Let function which doesn’t exist specifically for this scenario but it is the perfect solution for it.
str?.let { printText(it) }
which is equal to
if (str != null) { printText(str) }
and we can use the let function whenever you want to call a function but you just want to make sure no nullPointerException will be called:).
The Equality
I know we talked about kotlin Equality and we know that it is checking here for structural equality meaning that it refers to the .equals function, before but just a small note, if we tried to do this
val str4 : String? = null val anotherStr = "This isn't nullable" println(str4 == anotherStr)
we won’t get an exception even though we are comparing a nullable string (here it is null already) with non-nullable string.
why? because in Kotlin this operator is a safe operator, so instead of doing ==? which will be silly, to be honest, Kotlin just made the == checks for the null check under the covers for us.