I have pretty common piece of kotlin code here:
fusedLocationProviderClient.lastLocation.addOnSuccessListener { location: Location? ->
val geoCoder = Geocoder(this, Locale.getDefault())
val addr = geoCoder.getFromLocation(location.latitude, location.longitude, 1)
Toast.makeText(this, "Got location info", Toast.LENGTH_SHORT).show()
locationText.text = addr.get(0).toString()
}.addOnFailureListener { exception: Exception ->
locationText.text = exception.message
}
Since the location value from the callback can be null in certain cases we have to define it as a nullable type like so location: Location?. The problem arises when I want to use the latitude and longitude attributes from the location object like location.longitude. The compiler gives the following error:
Only safe (?.) or non-null asserted calls are allowed on nullable reciever of type Locaion?
Now I know doing location!!.latitude is a dangerous thing because it claims the value to not be null. And using location?.latitude gives me a type mismatch Required: Double Found: Double?
I've seen this happening many times while making async calls. My question is what is the official "kotin" way to handle situations like these?
Kotlin, unlike Java and many other languages, requires that you explicitly identify a nullable value as nullable or it will throw up a compiler error (as you've discovered). This is done to prevent the dreaded NullPointerException, an effect of the so-called billion dollar mistake (programmers the world over forgetting to check for null before assuming a variable's value is not null, and causing a NPE).
There are three ways to go about handling what you're asking about in Kotlin, and it boils down to a stylistic preference on your part plus a bit about how much code is conditioned upon the null/non-null status of the value. The methods all incorporate a null check.
For purposes of this answer, I'll assume if the latitude property is null, you want to throw an error. But one great thing about explicit nullability in Kotlin is it forces you to think about how you actually want to handle null values (is it an error that halts your code? do you plug in a default value and continue your code? etc.)
First, you can use the traditional if/else. For personal aesthetic reasons, I tend not to use this in Kotlin. I just enjoy using the other methods because they're "new" to me, coming from C-like languages, where if/else is old hat.
val myVal: Location? = someValue
if(myVal == null) {
throw IllegalStateException("myVal is null")
} else {
/* handle the non-null case(s) */
}
Second, you can use one of the Kotlin scoping functions (they are all used in subtly different ways but are interchangeable for the purposes of your question).
myValue.let tells Kotlin to stick myValue into the following code block but renamed to it. But myValue?.let tells Kotlin to do this only if myValue is non-null. If myValue is null, the block of code following let will not execute. If you put a ?: and some code after the block of code, that will be run if myValue is null:
val myVal: Location? = someValue
myVal?.let { location ->
/* handle the non-null case */
} ?: throw IllegalStateException("myVal is null")
In the above, throw ... only executes if myVal is null. If myVal is non-null, it will not throw.
The third option is similar to the second:
val myVal: Location? = someValue
myVal ?: throw IllegalStateException("myVal is null")
/* now handle the non-null case */
Remember the ?: from above? That's it again, and it operates the same way: if myVal is null, it will execute what comes to the right of it. In this case, a throw. If this were in a function, you could also do myVal ?: return someDefaultValue for example.
It operates as a type guard and ensures that for any subsequent code, myVal cannot be null (because myVal is immutable and we've now determined it's not null).
For nullable variable you need to check first variable is not null.
You can do using below methods:
if(location != null){
val latitude = location.latitude
}
or
location?.let{
val latitude = it.latitude // location can be replace with **it**
}
Related
private fun defaultOptions() {
val options = ArrayList<TextView>()
tvoptionone?.let { options.add(0, it) }
}
I am currently using the add(index, element) method in kotlin, However, I don't seem to understand what it represents in the element parameter of the add method.
These are the parameters for the add method I am trying to use
add(index, element)
it is the context object on which you've used the let function.
As you've used it with safe call operator (?.) it would only call let if object is non null.
Using ?.let ensures the lambda to be executed only when the object is non null. ?. ensures that object has to be non null and let makes that object available as it inside the lamda.
Here
tvoptionone?.let { options.add(0, it) }
it is a TextView as tvoptionone is a TextView, and it has a value same as tvoptionone.
In the below code
tvoptionone?.let { options.add(0, it) } }
it refers to tvoptionone
notice that lambda passed to let will be called only when tvoptionone is not null, so here it refers to tvoptionone and its value is not null
Questionmark after variable tvoptionone indicates that this variable can be null. If you write just:
options.add(0, tvoptionone)
and variable happens to be null then the add method will throw an error with wording like param element cannot be null or so.
Keyword let, in this particular example, is kind of a guardian against passing null into add method. If tvoptionone has some value (is not null) then it will be tvoptionone itself. Otherwise add method will not be called at all and compilation error will be avoided.
Scope functions are the ones you run on a value, and provide a function to run using that value. There's two kinds of scope functions in Kotlin - the ones where the value is passed in as a parameter (let, also etc.) and the ones where it becomes this (run, apply etc). They work the same, it just changes how you interact with the value - sometimes one is more convenient or suitable than the other
it is just the default name for the parameter passed in:
// these two are the same thing
name.let { println("Hi $it") }
name.let { it -> println("Hi $it") }
// rename it to something that reads better if you like
personData.firstName.let { name -> println("Hi $name") }
People have mentioned the null-check feature, where you can make the let block only run if the value is non-null:
name?.let { println("Hi $it, looking very not-null today") }
but another use for it is creating a temporary variable. If you have a var, it's possible the value will change while you're using it, so it's common to take a copy of it (so you know your copy won't change):
var importantNumber = 123
if (importantNumber > 100) {
// but it might have just been changed by another thread / coroutine and be < 100!
doThing(importantNumber)
}
var importantNumber = 123
val copy = importantNumber
if (copy > 100) {
// the copy can't change, so we know once we've checked it, it's fine
doThing(copy)
}
since let creates a variable to pass in as a parameter, it's basically making a copy in the same way:
var importantNumber = 123
importantNumber.let { if (it > 100) doThing(it) } // safe because 'it' won't change
and that's super important for nullable vars - if you check they're null, you need to know they'll stay null. Using ?.let guarantees that the value passed in as it will be non-null, because it's a copy that's been null-checked
This question already has answers here:
What's the difference between !! and ? in Kotlin?
(6 answers)
Closed 3 years ago.
I am a bit confused about the usage of ? and !! in the following instance.
lat = mLastLocation?.latitude.toString()
longi = mLastLocation!!.longitude.toString()
Which null-safety operator should I be using?
TL;DR:
?. operator is safe. Use it when you are unsure about the chain nullability.
!!. operator is meant to be used only when you are sure that the previous chain operation result is not null. Otherwise, crash.
if mLastLocation is never null, feel safe about using !!. (And about rethinking a little bit your code), otherwise, use ?.
Introduction
You have hit one of the best (and most useful) points while coding in Kotlin.
here which null safety operator I should use?
It depends on the behavior you want to achieve.
In Kotlin, you have to be very specific about what you want to do with null values, because the language is designed to be null-safe out of the box.
Of course, targeting the JVM brings many challenges to a programming language. The eventuality of having null values is one of these, and Kotlin, as we'll see, handles this in a really smart manner.
Purpose
We could explain the full theory behind those two operators, but I believe an example is really all you need.
Suppose you have a class, called Location, which we will declare in a nullable variable.
In Kotlin, this is represented as val location: Location?
Let's also say Location class has a property called lat, which is a nullable String, and a lon non-nullable String.
data class User(val lat: String?, val lon: String)
Operator ?.
Kotlin Safe Call Operator Docs
This operator is the safe call operator.
If you use it in a call chain, it is checking that your code chain goes onto the next element just if the previous element is not null. Otherwise, null is retuned from the statement.
val location: Location? = getLocation()
println(location.lat) // Compile-time error.
println(location?.lat) // Works fine.
This happens because in the first case, the object before ?. is nullable, thus the Kotlin Compiler infers that accessing a nullable property can lead to NPEs.
location could be null or not-null.We just don't know what it will be, and the Kotlin environment strictly makes sure that you are handling the eventuality of that value being null, as the type of our references variable is defined as nullable.
However, a certain variable being null is something you developer may not know. Sometimes it is not even up to you to receive a null or non-null value.
In this case you can safely stick with ?, knowing that this operator is your friend if you are unsure about whether what you're referencing will be null.
val location: Location = getSafeLocation()
val nullableLocation: Location? = getLocation()
// Fine, may print "null" or the value, if present.
// println accepts nullable values
println(location.lar)
// 100% sure it'll print the corrisponding String value
println(location.lon)
// May print "null", "null", or the lat String value.
// The first "null" is because the ? operator will check if
// nullableLocation is null. If it is, it stops the execution
// chain and returns null. Otherwise, it assumes nullableLocation is safe
// and goes on.
//
// The second "null" is because the value itself of lat
// is declared as String? and Kotlin knows it may be null.
// If println() did not accept null values, this call would fail,
// but instead it prints "null" in case lat is indeed null.
println(nullableLocation?.lat)
// Since lat was the last element of the chain, it is not
// delivered as the parameter type anymore, and thus if we
// want to read a property from it we have to ensure that it isn't null.
println(nullableLocation?.lat?.length)
// This, as you may guess, returns wither null in case nullableLocation is null,
// otherwise 100% sure it will print lon value, since it is not a String? but a String.
println(nullableLocation?.lon)
Operator !!.
Kotlin Double-Bang Operator Docs
This is the dreaded double-bang operator.
Talking about syntax, it is very similar to ?., since it is used in the same place.
To describe it in a really simple way: if anything before the call is null, your code will crash. Instantly. Without warnings.
With !!. you're explicitly saying that
Kotlin has to ignore any type nullability marker and to perform the operation you intend, even though it enters in a kind of danger zone.
This is known as a force, because you're forcing the Kotlin environment to believe that the previous statement is not null.
This operator best use case is when porting another library to Kotlin, or while handling API RESTful responses, situations where null values may come in, but because of environment/platform reasons, you know that some value can not be null. This helps you bringing type safety in the Kotlin world in the first place, if used properly.
But for mainstream software, this feature is meant for a really specific and narrow usage: If you are 100% sure that the previous call is not null, go ahead.
val location: Location? = getLocation()
println(location!!.lon)
The previous code may crash if location is
Which one to use
Both operators are type-transforming. They both turn nullable values into non-nullable ones. The way the do it is the changing factor.
As a general rule, if you're sure the value you are targeting is not null, use !!., otherwise stick with ?.
if you define a variable as
var myFirstVar:String? = null
this means that "myFirstVar" can have a null value and when you use "myFirstVar" you should indicate whether or not it has a null value
myFirstVar!!.toString
in here you're saying that you're 100% that myFirstVar will not be null (maybe you've given it a value before calling it)
but if you use ?
myFirstVar?.toString
you're indicating that myFirstVar might have a null value, the ? will chick if myFirstVar is null or not, if it is then it will not convert it to string (the application will not crash) and if it wasn't then it will convert it to string, it is a safety check to reduce the null crashes.
If a variable is declared as nullable type, you have two options when using it.
Let's take this for example:
private var myButton: Button? = null
So you have two option for the myButton. You can evaluate it, or keep it as it is. But the program on the run doesn't know what you have done with the variable before. So, in order to be safe Kotlin language provides you with ? and !! operators. One is for the safety of program, so it won't crash and cause a KNPE:
myButton?.setOnClickListener{
}
If the button is null, the app won't crash. Now, if you are 100% sure that you have evaluated the Button with a value different from null, you can use !!:
myButton!!.setOnClickListener{
}
In this case, if you run the program and the myButton is null, you will have a crash.
Null Safety Myth
However, this is not a null safety case (I guess). What people mean by null safety in Kotlin is exactly this:
private val myButton: Button = someButtonInitialization()
If you evaluate it to null, the compiler would yell at you because Button is a non nullable type. Otherwise it would be Button?.
This is null safety IMO, and not !! or ?.
Special case: You can have:
private lateinit var myButton: Button
If you never evaluate the myButton you will never have KNPE, but an UninitializedPropertyException which has nothing to do with Null threat or null safety.
Let's have an example
var a: String? = "Hello world!"
fun test1() {
a?.trim()
}
fun test2() {
a!!.trim()
}
The first decompiled function is:
public static final void test1() {
String var10000 = a;
if (var10000 != null) {
String var0 = var10000;
StringsKt.trim((CharSequence)var0).toString();
}
}
The second decompiled function is:
public static final void test2() {
String var10000 = a;
if (var10000 == null) {
Intrinsics.throwNpe();
}
String var0 = var10000;
StringsKt.trim((CharSequence)var0).toString();
}
Where Intrinsics.throwNpe(); is defined as:
public static void throwNpe() {
throw sanitizeStackTrace(new KotlinNullPointerException());
}
So a?.trim() will do nothing if var a was null
So a!!.trim() will throw an exception if var a was null
I don't understand why Android Studio is not able to tell that, although SharedPreferences declares the defValue of getString as #Nullable, the current value is actually not null!
The result of the following call:
myFunction(getSharedPreferences().getString(MY_SETTING_NAME.name(), "This string is not null"))
will trigger a warning:
Argument might be null
How can it be? Since defValue is actually not null and we know it...
The Android framework does not use Kotlin contracts and cannot change the #Nullable annotation on the return value based on whether the defValue you pass is null or not.
As an alternative, you should consider using Kotlin's elvis operator and writing code such as:
myFunction(getSharedPreferences().getString(MY_SETTING_NAME.name(), null)
?: "This string is not null")
Which correctly evaluates as non-null.
I find a lot of arguments have the error
Type mismatch
required: FragmentActivity
found: FragmentActivity?
I'm not sure of what's the best way to address this problem.
Currently, I wrap the line in a variable?.let{ statement }
meViewModel = ViewModelProviders.of((iMainActivity as Fragment).activity, vmf).get(MeViewModel::class.java) }
into
val fragmentActivity = (iMainActivity as Fragment).activity
fragmentActivity?.let
{
meViewModel = ViewModelProviders.of(fragmentActivity, vmf).get(MeViewModel::class.java)
}
is it the right way to approach this
Short answer: Yes.
This means that the compiler is not sure if s.th. is !=null. If you are sure that it is not null you can also use:
val fragmentActivity = (iMainActivity as Fragment).activity!!
That gives you FragmentActivity instead of FragmentActivity? and you dont need the ?.let{}
Keep in mind that that might throw a NPE, while the
fragmentActivity?.let { fragment ->
meViewModel = ViewModelProviders.of(fragment, vmf).get(MeViewModel::class.java)
}
would simply not execute the block within .let{}, which is often less harmful then a NPE. See https://kotlinlang.org/docs/reference/null-safety.html for more.
Short answer: Yes.
With ?.let you can be sure that the value will be non null, so you have the null safety you would expect. Just keep in mind that in some cases you cannot use the smartcast which you did in your code above.
Smart casts [...] don't work on var properties, and they always work on local variables (val and var). They also don't work on val properties with a custom getter, because val doesn't mean final in Kotlin.
Quote from Marko Topolnik in the comments.
This is because, in a rare edge case, the value could be changed by a different thread. You will get a compile error so that is prevented too. In that case you would need to use the implicit it or define an own alias like here:
fragmentActivity?.let { fragment ->
meViewModel = ViewModelProviders.of(fragment, vmf).get(MeViewModel::class.java)
}
What's an idiomatic way to do code this in Kotlin?
private var someVar: SomeClass? = null
private fun getSomeVar(): SomeClass {
if (someVar == null) {
someVar = getDefaultSomeVar()
}
return someVar
}
Android Studio warns me about the return type. In Java this code is, however, proper and idiomatic. I mean, instead of changing the return type to SomeClass? maybe there's still a better way?
Actually, getSomeVar() can never return null
The compiler complains because, theoretically, a different thread could change someVar in between the assignment and the return statement.
The idiomatic solution here would be to use property delegation:
private val someVar: SomeClass by lazy { getDefaultSomeVar() }
This initializes the property when it is first accessed in a thread safe manner. Also note that it is now a non-nullable val, instead of a nullable var, which makes it generally easier to work with.
You do lose the ability to modify it later on. If it needs to be mutable you currently have to make that yourself. For an example implementation see this SO question: Kotlin lazy default property
The following two solutions take the method in the question (the 'java way') for granted and just show a way to prevent the compiler warning. However, in your situation these are not advised as they both have drawbacks over the lazy initialized property:
1) Introduce a local variable. This variable is safe from being mutated by other threads and allows the compiler to do a Smart Cast:
private fun getSomeVar(): SomeClass {
var value = someVar
if(value == null) {
value = getDefaultSomeVar()
someVar = value
}
return value
}
The method itself is however still not thread safe. In a multithreaded environment, getDefaultSomeVar() could be called multiple times and it is not guaranteed that the returned value of this method is equal to someVar.
2) Use !!: the double bang operator. This converts a nullable type to non-nullable. But now you lose the protection and null safety that the kotlin compiler enforces on you.
return someVar!!
As the documentation puts it: 'If you want an NPE, you can have it'
You can write:
return someVar!!
this will return a non-null value, however if it's null it will throw an NPE.
It could be shorter and without any warnings
private fun getSomeVar(): SomeClass {
return someVar?:getDefaultSomeVar()
}