访问Android传感器的惰性非Null属性时为Null属性
当通过访问Android传感器的惰性非Null属性时为Null属性,android,kotlin,kotlin-android-extensions,Android,Kotlin,Kotlin Android Extensions,当通过lazy初始化类型为Sensor的val时,编译器忽略返回的值可以是null private val sensorManager by lazy { getSystemService(Context.SENSOR_SERVICE) as SensorManager } private val proximitySensor: Sensor by lazy { sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) } 注意:val被声
lazy
初始化类型为Sensor
的val
时,编译器忽略返回的值可以是null
private val sensorManager by lazy { getSystemService(Context.SENSOR_SERVICE) as SensorManager }
private val proximitySensor: Sensor by lazy { sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) }
注意:val
被声明为传感器,而不是传感器?
private val sensorManager by lazy { getSystemService(Context.SENSOR_SERVICE) as SensorManager }
private val proximitySensor: Sensor by lazy { sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) }
sensorManager.getDefaultSensor(Sensor.TYPE_approxity)
也可以返回null
,并且该方法没有使用@Nullable
注释,因此在编译时无法对其进行检查
另外,Android Studio在检查null时会发出警告,因为我们没有将其声明为传感器?
将可空的赋值给val
非空的时,它不应该引发编译时错误吗
当访问值proximitySensor
时,如果该值为空,则会产生预期的运行时异常。
'java.lang.String android.hardware.Sensor.getName()'在空对象引用上
Kotlin标准库参考中的lazy()
,如下所示:
lazy()
返回存储lambda初始值设定项的lazy
实例
getter的第一个调用执行传递给lazy()
的lambda,然后
存储其结果
随后,getter执行返回存储的值
在进行赋值时不应该抛出异常吗
当我们尝试访问它时
运算符设置值(
有吗?,
属性:KProperty,值:字符串
) {
//分配
//分配发生时,此时应生成异常
}
多亏了你的问题,现在这是一个很好的回答
此答案的早期内容:
我对你的问题做了一个MCVE:
val sensorManager = SensorManager()
val proximitySensor: Sensor by lazy { sensorManager.sensor }
fun main(args: Array<String>) {
println(proximitySensor)
}
而且。。。你猜怎么着?它打印null
。我称之为“Kotlin bug”:
你问:
当赋值时,而不是当我们试图访问它时,不应该抛出异常吗
对于惰性
委托,只有当您第一次访问属性时才会发生赋值。这将传播到SynchronizedLazyImpl.value
getter,其中包含众所周知的双重检查惰性init习惯用法,并且这是您提供的初始值设定项块唯一运行的时间
即使没有详细讨论,延迟
委托的本质是将初始化推迟到可能的最晚时间,这是第一次属性访问。正确的实现将确保在不可为null的属性的计算完成之前引发异常。不幸的是,当前的实现不正确。是否应该有编译时错误?
当将可为null的值分配给非null的val时,它不应该引发编译时错误吗
是的,但这里不是这样的情况在本例中,您将a赋值给您的值,并告诉编译器将其视为不可为空。应该有一个运行时错误IllegalStateException
——正如@MarkoTopolnik指出的,这是一个bug
缺陷
此错误已被覆盖。这里有一个与学员直接相关的问题。
还有一个讨论主题和一些可运行的示例
何时将引发运行时异常?
当您使用proximitySensor
时,将触发该错误,该方式需要一个不可为空的值,例如:
val s: Sensor = proximitySensor
proximitySensor.someMethod()
println(proximitySensor.someProperty)
但是当属性初始化时,这不会引发异常!我们可以解决这个问题
为什么首次初始化Lazy属性时没有错误?
由于sensorManager.getDefaultSensor(Sensor.TYPE\u approxity)
是用java实现的,因此它返回一个值。因此,惰性委托的类型为,Lazy
懒惰类运行初始值设定项lambda。保存lambda的结果,然后以类型T
返回,即传感器代码>
解决方案
如果在调用lazy
函数时显式声明类型params:
private val proximitySensor: Sensor by lazy<Sensor> { sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) }
在惰性初始值设定项内提供默认值
正如您所提到的,sensorManager.getDefaultSensor(Sensor.TYPE\u approxity)
可能返回null。我们可以返回一个默认值:
val proximitySensor: Sensor by lazy {
sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) ?: SOME_DEFAULT_VALUE
}
关于平台类型的注释
Kotlin中的平台类型允许您(调用方)决定类型是可为null还是不可为null,从而使使用Java更加实用。假设Java中的所有内容都可以为null,这意味着您将不得不进行大量痛苦的null检查,即使Java代码从不返回null
*注意:如果您正在编写Java代码,可以使用@Nullable
和@NonNull
注释向Kotlin编译器以及其他静态分析工具提供元数据。Spring框架等库
以下是Kotlin开发人员Andrey Breslav的文章,他深入讲述了平台类型的互操作性设计决策。因为这是一个返回传感器的Java API调用代码>@m0skit0,但这里没有赋值<代码>惰性
是一个属性委托。当您取消引用val
时,将调用其get()
方法。但是,如果由于取消引用proximitySensor
,而得到null
,这显然是Kotlin的错误。sensorManager.getDefaultSensor(Sensor.TYPE_Proximition)没有nullability注释,因此Kotlin相信您关于它是否可以为null的问题。@MarkoTopolnik我认为它的意思是“委派时间”其中,proximitySensor
被“分配”了一个lazydegate
——它发生在编译时。@harsh\u v良好的编辑。我已经更新了关于懒惰n的答案
private val proximitySensor: Sensor? by lazy { sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) }
val proximitySensor: Sensor by lazy {
sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) ?: SOME_DEFAULT_VALUE
}