Должна ли быть ошибка времени компиляции?
Разве это не должно вызывать ошибку времени компиляции при присвоении нулю значения val, отличного от NULL?
Да, но это не то, что здесь происходит В этом случае вы присваиваете тип платформы своему значению и указываете компилятору обрабатывать его как ненулевое значение. Должна быть ошибка времени выполнения IllegalStateException
- поскольку @MarkoTopolnik указывает, это ошибка .
ошибка
Эта ошибка покрыта KT-8135 . Вот связанная проблема, напрямую связанная с делегатами, KT-24258 .
Здесь также есть тема для обсуждения с несколькими работающими примерами здесь .
Когда будет выдано исключение времени выполнения?
Ошибка будет вызвана, если вы используете proximitySensor
способом, который требует значения, не равного нулю, например:
val s: Sensor = proximitySensor
proximitySensor.someMethod()
println(proximitySensor.someProperty)
Но это не приведет к исключению при инициализации свойства! Мы можем это исправить ...
Почему нет ошибки при первой инициализации свойства Lazy?
Так как sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
реализован в Java, он возвращает тип платформы . Поэтому делегат Lazy имеет тип Lazy<Sensor!>
.
Класс Lazy запускает лямбду-инициализатор. Результат лямбда сохраняется и затем возвращается как тип T
, который является Sensor!
.
Решение
Если мы явно объявим params типа при вызове функции lazy
:
private val proximitySensor: Sensor by lazy<Sensor> { sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) }
Тогда будет выброшено исключение, как только будет получено ленивое значение.
Другие опции
Объявить бесконтактный датчик как обнуляемый
Предупреждение направляет вас в правильном направлении, либо не проверяйте нулевое значение, либо объявляйте его обнуляемым Скажите компилятору, что значение следует рассматривать как обнуляемое, явно объявив тип обнуляемым:
private val proximitySensor: Sensor? by lazy { sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) }
Укажите значение по умолчанию внутри ленивого инициализатора
Как вы упомянули, sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
может возвращать ноль. Мы могли бы вернуть значение по умолчанию:
val proximitySensor: Sensor by lazy {
sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY) ?: SOME_DEFAULT_VALUE
}
Примечание о типах платформ
Типы платформ в Kotlin делают работу с Java более прагматичной, позволяя вызывающей стороне решать, является ли тип обнуляемым или не обнуляемым. Альтернатива предположить, что все в Java является nullable, означала бы, что вам пришлось бы делать много мучительной проверки нуля, даже если код Java никогда не возвращает null.
* Примечание. Если вы пишете код Java, вы можете использовать аннотации @Nullable
и @NonNull
для предоставления метаданных компилятору Kotlin, а также другим инструментам статического анализа. Библиотеки, такие как Spring Framework , сделали это со своими API .
Вот доклад Андрея Бреслава, разработчика Kotlin, который подробно рассказывает об этом проектном решении типов платформ для обеспечения взаимодействия.