将可空值传递给函数的最佳方法

时间:2019-12-03 05:24:04

标签: android kotlin null

我在这里有很常见的kotlin代码:

        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
        }

由于在某些情况下回调的位置值可以为null,因此我们必须将其定义为nullable类型,例如location: Location?。当我想使用诸如location.longitude之类的位置对象的经度和纬度属性时,就会出现问题。编译器给出以下错误:

Only safe (?.) or non-null asserted calls are allowed on nullable reciever of type Locaion?

现在我知道做location!!.latitude是一件危险的事情,因为它声称该值不为null。并且使用location?.latitude给我一个类型不匹配的Required: Double Found: Double?

在进行异步调用时,我已经多次看到这种情况。我的问题是,处理此类情况的官方“科廷”方式是什么?

2 个答案:

答案 0 :(得分:0)

对于可为空的变量,您需要检查第一个变量不为空。

您可以使用以下方法:

if(location != null){
   val latitude = location.latitude
}

or 

location?.let{
   val latitude = it.latitude // location can be replace with **it**
}

答案 1 :(得分:0)

与Java和许多其他语言不同,Kotlin要求您将可空值明确标识为可空值,否则它将引发编译器错误(如您所知)。这样做是为了防止可怕的NullPointerException(所谓的billion dollar mistake的影响)(程序员在假设变量的值不为null之前忘记检查null并导致了NPE)。

有三种方法可以处理您在Kotlin中所要解决的问题,它归结为您的风格偏好,还有一点关于多少代码取决于条件的null / non-null状态。值。这些方法都包含一个空检查。

出于此答案的目的,我将假设l​​atitude属性为null,则要抛出错误。但是Kotlin中显式可为空性的一个很棒的事情是,它迫使您考虑实际上如何处理空值(是错误导致代码暂停吗?您是否插入默认值并继续执行代码?等)< / p>

首先,您可以使用传统的if/else。由于个人审美的原因,我倾向于在Kotlin中不使用它。我只是喜欢使用其他方法,因为它们对我来说是“新的”,来自类似于C的语言,在这些语言中if / else是旧帽子。

val myVal: Location? = someValue

if(myVal == null) {
   throw IllegalStateException("myVal is null")
} else {
   /* handle the non-null case(s) */
}

第二,您可以使用Kotlin scoping functions中的一种(它们的使用方式略有不同,但出于您的问题可以互换)。

myValue.let告诉Kotlin将myValue粘贴到以下代码块中,但重命名为it。但是myValue?.let告诉Kotlin仅在myValue不为null的情况下执行此操作。如果myValue为null,则let之后的代码块将不会执行。如果将?:和一些代码放在代码块之后,则在myValue为null的情况下将运行该代码:

val myVal: Location? = someValue

myVal?.let { location ->
   /* handle the non-null case */
} ?: throw IllegalStateException("myVal is null")

在上面,throw ...仅在myVal为null时执行。如果myVal不为null,则不会抛出该错误。

第三个选项类似于第二个:

val myVal: Location? = someValue

myVal ?: throw IllegalStateException("myVal is null")

/* now handle the non-null case */

还记得上方的?:吗?就是这样,它的运行方式也一样:如果myVal为null,它将执行它右边的内容。在这种情况下,抛出。如果这在函数中,您也可以执行myVal ?: return someDefaultValue

它用作类型保护,并确保对于任何后续代码,myVal 不能为null(因为myVal是不可变的,我们现在确定它不为null)。